Hanye官网
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

generateRoutes.js 8.9KB

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