Hanye官网
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

generateRoutes.js 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import fs from 'fs';
  2. import path from 'path';
  3. import { fileURLToPath } from 'url';
  4. import { parse } from 'yaml';
  5. const __filename = fileURLToPath(import.meta.url);
  6. const __dirname = path.dirname(__filename);
  7. /**
  8. * 读取Markdown文件的frontmatter部分
  9. * @param {string} filePath - Markdown文件路径
  10. * @returns {Object} - frontmatter数据对象
  11. */
  12. function readMarkdownFrontmatter(filePath) {
  13. try {
  14. const content = fs.readFileSync(filePath, 'utf-8');
  15. const frontmatterMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/m);
  16. if (frontmatterMatch && frontmatterMatch[1]) {
  17. try {
  18. const yamlContent = frontmatterMatch[1].trim();
  19. console.log(`解析文件: ${filePath}`);
  20. console.log(`YAML内容:\n${yamlContent}`);
  21. const metadata = parse(yamlContent);
  22. console.log(`解析结果:`, metadata);
  23. // 确保所有字段都有默认值
  24. return {
  25. title: metadata.title || '',
  26. name: metadata.name || metadata.title || '',
  27. description: metadata.description || '',
  28. summary: metadata.summary || '',
  29. usage: Array.isArray(metadata.usage) ? metadata.usage : [],
  30. categoryId: metadata.categoryId || '',
  31. category: metadata.category || '',
  32. image: metadata.image || '',
  33. series: Array.isArray(metadata.series) ? metadata.series : [],
  34. gallery: Array.isArray(metadata.gallery) ? metadata.gallery : [],
  35. capacities: Array.isArray(metadata.capacities) ? metadata.capacities : [],
  36. products: Array.isArray(metadata.products) ? metadata.products : [],
  37. id: metadata.id || ''
  38. };
  39. } catch (err) {
  40. console.error(`解析frontmatter失败: ${filePath}`, err);
  41. return {};
  42. }
  43. }
  44. return {};
  45. } catch (err) {
  46. console.error(`读取文件失败: ${filePath}`, err);
  47. return {};
  48. }
  49. }
  50. /**
  51. * 获取所有产品ID和详细信息的函数
  52. * @param {string} locale - 语言代码
  53. * @returns {Object[]} - 产品信息数组
  54. */
  55. function getProducts(locale) {
  56. try {
  57. const productsDir = path.resolve(__dirname, '../content/products', locale);
  58. if (!fs.existsSync(productsDir)) {
  59. console.log(`找不到产品目录: ${productsDir}`);
  60. return [];
  61. }
  62. // 读取所有.md文件
  63. const productFiles = fs.readdirSync(productsDir)
  64. .filter(file => file.endsWith('.md'));
  65. console.log(`找到 ${locale} 语言的产品文件: ${productFiles.length}个`);
  66. // 读取每个产品文件的frontmatter
  67. return productFiles.map(file => {
  68. const filePath = path.join(productsDir, file);
  69. const metadata = readMarkdownFrontmatter(filePath);
  70. console.log(`metadata: ${JSON.stringify(metadata)}`);
  71. const id = path.basename(file, '.md');
  72. // 使用原始图片路径,如果没有则使用默认路径
  73. const imagePath = metadata.image;
  74. return {
  75. id,
  76. title: metadata.title || id,
  77. name: metadata.name || metadata.title || id,
  78. usage: metadata.usage || [],
  79. category: metadata.categoryId || '',
  80. image: imagePath,
  81. description: metadata.description || '',
  82. summary: metadata.summary || '',
  83. series: metadata.series || [],
  84. gallery: metadata.gallery || [],
  85. capacities: metadata.capacities || []
  86. };
  87. });
  88. } catch (err) {
  89. console.error(`获取产品信息时出错 (${locale}):`, err);
  90. return [];
  91. }
  92. }
  93. /**
  94. * 获取所有用途类别
  95. * @param {string} locale - 语言代码
  96. * @returns {Object[]} - 用途类别数组
  97. */
  98. function getUsages(locale) {
  99. try {
  100. const usagesDir = path.resolve(__dirname, '../content/usages', locale);
  101. if (!fs.existsSync(usagesDir)) {
  102. console.log(`找不到用途目录: ${usagesDir}`);
  103. return [];
  104. }
  105. // 读取所有.md文件
  106. const usageFiles = fs.readdirSync(usagesDir)
  107. .filter(file => file.endsWith('.md'));
  108. // 读取每个用途文件的frontmatter
  109. return usageFiles.map(file => {
  110. const filePath = path.join(usagesDir, file);
  111. const content = fs.readFileSync(filePath, 'utf-8');
  112. const frontmatterMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/m);
  113. if (frontmatterMatch && frontmatterMatch[1]) {
  114. try {
  115. const yamlContent = frontmatterMatch[1].trim();
  116. const metadata = parse(yamlContent);
  117. const id = path.basename(file, '.md');
  118. return {
  119. id: metadata.id || id,
  120. title: metadata.title || id
  121. };
  122. } catch (err) {
  123. console.error(`解析frontmatter失败: ${filePath}`, err);
  124. return {};
  125. }
  126. }
  127. return {
  128. id: path.basename(file, '.md'),
  129. title: path.basename(file, '.md'),
  130. };
  131. });
  132. } catch (err) {
  133. console.error(`获取用途信息时出错 (${locale}):`, err);
  134. return [];
  135. }
  136. }
  137. /**
  138. * 获取所有分类
  139. * @param {string} locale - 语言代码
  140. * @returns {Object[]} - 分类数组
  141. */
  142. function getCategories(locale) {
  143. try {
  144. const categoriesDir = path.resolve(__dirname, '../content/categories', locale);
  145. if (!fs.existsSync(categoriesDir)) {
  146. console.log(`找不到分类目录: ${categoriesDir}`);
  147. return [];
  148. }
  149. // 读取所有.md文件
  150. const categoryFiles = fs.readdirSync(categoriesDir)
  151. .filter(file => file.endsWith('.md'));
  152. console.log(`找到 ${locale} 语言的分类文件: ${categoryFiles.length}个`);
  153. // 读取每个分类文件的frontmatter
  154. return categoryFiles.map(file => {
  155. const filePath = path.join(categoriesDir, file);
  156. const metadata = readMarkdownFrontmatter(filePath);
  157. const id = path.basename(file, '.md');
  158. return {
  159. id,
  160. title: metadata.title,
  161. description: metadata.description,
  162. image: metadata.image,
  163. summary: metadata.summary,
  164. capacities: metadata.capacities,
  165. sort: metadata.sort,
  166. };
  167. });
  168. } catch (err) {
  169. console.error(`获取分类信息时出错 (${locale}):`, err);
  170. return [];
  171. }
  172. }
  173. // 定义基础路由和支持的语言
  174. const baseRoutes = [
  175. '/',
  176. '/products',
  177. '/faq',
  178. '/contact',
  179. '/about',
  180. ];
  181. const locales = ['ja', 'en', 'zh'];
  182. // 生成所有路由
  183. function generateAllRoutes() {
  184. let routes = [...baseRoutes];
  185. // 添加语言前缀路由 zh 是默认语言
  186. locales.forEach(locale => {
  187. if (locale !== 'zh') {
  188. routes.push(`/${locale}`);
  189. baseRoutes.forEach(route => {
  190. if (route !== '/') {
  191. routes.push(`/${locale}${route}`);
  192. }
  193. });
  194. }
  195. });
  196. // 为每个语言添加产品详情页路由
  197. locales.forEach(locale => {
  198. const products = getProducts(locale);
  199. const prefixPath = locale === 'zh' ? '' : `/${locale}`;
  200. products.forEach(product => {
  201. routes.push(`${prefixPath}/products/${product.id}`);
  202. });
  203. // 添加按用途筛选的产品列表页
  204. const usages = getUsages(locale);
  205. usages.forEach(usage => {
  206. routes.push(`${prefixPath}/products?usage=${encodeURIComponent(usage.title)}`);
  207. });
  208. // 添加按分类筛选的产品列表页
  209. const categories = getCategories(locale);
  210. categories.forEach(category => {
  211. routes.push(`${prefixPath}/products?category=${category.id}`);
  212. });
  213. });
  214. // 移除重复项
  215. routes = [...new Set(routes)];
  216. console.log(`总共生成了 ${routes.length} 条路由`);
  217. return routes;
  218. }
  219. // 生成路由并保存到文件
  220. const routes = generateAllRoutes();
  221. fs.writeFileSync(path.resolve(__dirname, '../prerenderRoutes.json'), JSON.stringify(routes, null, 2));
  222. console.log('路由生成完成,已保存到 prerenderRoutes.json');
  223. // 输出数据文件,供前端使用
  224. function generateDataFiles() {
  225. const dataDir = path.resolve(__dirname, '../public/data');
  226. // 确保目录存在
  227. if (!fs.existsSync(dataDir)) {
  228. fs.mkdirSync(dataDir, { recursive: true });
  229. }
  230. // 为每种语言生成产品数据
  231. locales.forEach(locale => {
  232. const products = getProducts(locale);
  233. const usages = getUsages(locale);
  234. const categories = getCategories(locale);
  235. // 保存产品数据
  236. fs.writeFileSync(
  237. path.resolve(dataDir, `products-${locale}.json`),
  238. JSON.stringify(products, null, 2)
  239. );
  240. // 保存用途数据
  241. fs.writeFileSync(
  242. path.resolve(dataDir, `usages-${locale}.json`),
  243. JSON.stringify(usages, null, 2)
  244. );
  245. // 保存分类数据
  246. fs.writeFileSync(
  247. path.resolve(dataDir, `categories-${locale}.json`),
  248. JSON.stringify(categories, null, 2)
  249. );
  250. });
  251. console.log('数据文件生成完成,已保存到 public/data 目录');
  252. }
  253. // 生成数据文件
  254. generateDataFiles();