Hanye官网
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

generateRoutes.js 8.7KB

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