Skip to content

Vite构建自动生成路由插件

javascript
import fs from 'fs';
import path from 'path';

/**
 * 从项目名中提取排序序号和名称。
 * @param {string} item - 项目名称(如 "01-introduction")。
 * @returns {Object} - 包含序号和名称的对象。
 * @property {number} order - 序号(如果没有序号,则为 -1)。
 * @property {string} name - 名称(去除序号后的部分)。
 */
function extractOrderAndName(item) {
  // 使用正则表达式匹配项目名,提取序号和名称
  const match = item.match(/^(\d+)?[-_]?(.*)/);
  // 如果有序号,将其转换为整数,否则序号为 -1
  const order = match[1] ? parseInt(match[1], 10) : -1;
  const name = match[2]; // 名称为正则表达式匹配的第二部分
  return { order, name };
}

/**
 * 生成侧边栏的函数。
 * @param {string} basePath - 基础路径(如 '/guide/work/'),用于生成侧边栏的链接。
 * @param {boolean} [collapsed=true] - 是否将侧边栏组设置为可折叠,默认折叠。
 * @returns {SidebarItem[]} - 生成的侧边栏数组,包含目录和文件的链接信息。
 */
function generateSidebar(basePath, collapsed = true) {
  const sidebar = []; // 初始化空的侧边栏数组
  // 将 basePath 转换为目录路径(如 '/guide/work/' -> './docs/guide/work/')
  const directoryPath = path.join('./docs', basePath);
  const items = fs.readdirSync(directoryPath); // 同步读取目录下的所有项目(文件和子目录)

  // 对项目进行排序,根据提取的序号进行排序
  const sortedItems = items.sort((a, b) => {
    const aInfo = extractOrderAndName(a);
    const bInfo = extractOrderAndName(b);

    // 如果两个项目都没有序号,按名称进行字母排序
    if (aInfo.order === -1 && bInfo.order === -1) {
      return aInfo.name.localeCompare(bInfo.name);
    }

    // 如果一个项目没有序号,将其排在有序号的项目后面
    if (aInfo.order === -1) return 1;
    if (bInfo.order === -1) return -1;

    // 如果两个项目都有序号,按序号进行排序
    return aInfo.order - bInfo.order;
  });

  // 遍历排序后的项目
  sortedItems.forEach((item) => {
    const itemPath = path.join(directoryPath, item); // 拼接项目的完整路径
    const stat = fs.statSync(itemPath); // 同步获取项目的文件状态

    // 判断项目是否为目录
    if (stat.isDirectory()) {
      // 递归调用 generateSidebar 函数处理子目录
      const nestedSidebar = generateSidebar(path.join(basePath, item), collapsed);
      // 如果子目录有内容,将其添加到侧边栏数组中
      if (nestedSidebar.length > 0) {
        const { name } = extractOrderAndName(item); // 提取目录名,去除序号
        sidebar.push({
          text: name, // 目录名作为侧边栏文本
          collapsed, // 使用传入的 collapsed 参数控制是否折叠
          items: nestedSidebar // 嵌套的侧边栏作为子项
        });
      }
    } else if (stat.isFile() && item.endsWith('.md')) {
      // 判断项目是否为 Markdown 文件
      const { name } = extractOrderAndName(item); // 提取文件名,去除序号
      const title = name.replace(/\.md$/, ''); // 从文件名中去掉 .md 后缀,作为侧边栏文本
      sidebar.push({
        text: title, // 文件名作为侧边栏文本
        link: path.join(basePath, item.replace(/\.md$/, '')) // 生成该 Markdown 文件的链接
      });
    }
  });
  // 返回生成的侧边栏数组
  return sidebar;
}

// 导出 generateSidebar 函数生成的 sidebar,以便在其他模块中使用
export { generateSidebar };