海哥 发表于 2025-4-13 19:08:36

【VitePress】新增md文件后主动更新侧边栏导航

说在前面

   

[*]操作系统:windows11
[*]node版本:v18.19.0
[*]npm版本:10.2.3
[*]vitepress版本:1.6.3
[*]完备代码:github
先看结果



[*]模板用的就是官方主题
https://i-blog.csdnimg.cn/direct/e6066b58e24d45308acd9453777c9a83.png
https://i-blog.csdnimg.cn/direct/7dc5fea50e2649b3b483bad56ac79c48.png
代码结构

https://i-blog.csdnimg.cn/direct/5fc658328b924c6a88f3b19eb924472f.png
具体说明

侧边栏格式



[*]通常,侧边栏定义在config.mts中export default {
themeConfig: {
    sidebar: [
      {
      text: 'Guide',
      items: [
          { text: 'Introduction', link: '/introduction' },
          { text: 'Getting Started', link: '/getting-started' },
          ...
      ]
      }
    ]
}
}
例如上述代码定义了这样子的侧边栏:
https://i-blog.csdnimg.cn/direct/efbd65c37df34368a5d2282f47ac4da2.png
[*]而如今,我们需要根据目录内容,主动天生一个侧边栏
utils



[*]在该目录下,我们实现了一个脚本,用于主动天生侧边栏内容import FastGlob from 'fast-glob';
const { glob } = FastGlob
import fs from 'fs/promises';
import path from 'path';
import type { DefaultTheme } from 'vitepress';
import chokidar from 'chokidar';

type SidebarConfig = Record<string, DefaultTheme.SidebarItem[]>;

export async function generateAutoSidebar(): Promise<SidebarConfig> {
    const basePath = path.join(process.cwd(), 'doc/reviews');
    const branches = await glob('*/', {
      cwd: basePath,
      onlyDirectories: true,
      deep: 1
    });

    const sidebar: DefaultTheme.SidebarItem[] = [];

    for (const branchDir of branches) {
      const branchName = branchDir.replace(/\/$/, '');
      const mdFiles = await glob(`${branchDir}/*.md`, {
            cwd: basePath,
            ignore: ['**/_*.md']
      });

      const items: DefaultTheme.SidebarItem[] = mdFiles
            .map(file => {
                const fileName = path.basename(file, '.md');
                return {
                  text: `${fileName}.md`,
                  link: `/reviews/${branchDir}/${fileName}`
                };
            })
            .sort((a, b) => {
                const numA = parseInt(a.text.match(/\d+/)?. || '0');
                const numB = parseInt(b.text.match(/\d+/)?. || '0');
                return numA - numB;
            });

      sidebar.push({
            text: branchName,
            collapsed: false,
            items
      });
    }

    return { '/reviews/': sidebar };
}

export async function writeSidebarConfig(): Promise<void> {
    const sidebarConfig = await generateAutoSidebar();
    const configContent = `// Auto-generated sidebar config
import type { DefaultTheme } from 'vitepress';

export const sidebarConfig: DefaultTheme.Config['sidebar'] = ${JSON.stringify(sidebarConfig, null, 2)};
`;

    var p = path.join(process.cwd(), 'doc/.vitepress/sidebar.generated.ts')

    await fs.writeFile(
      p,
      configContent
    );
}


writeSidebarConfig()

[*]通过执行tsx doc/.vitepress/utils/generateSidebar.ts --watch,将在./doc/.vitepress/目录下主动天生sidebar.generate.ts文件,以上述reviews文件夹中内容为例,天生的内容为:// Auto-generated sidebar config
import type { DefaultTheme } from 'vitepress';

export const sidebarConfig: DefaultTheme.Config['sidebar'] = {
"/reviews/": [
    {
      "text": "aaa",
      "collapsed": false,
      "items": [
      {
          "text": "1.md",
          "link": "/reviews/aaa/1"
      },
      {
          "text": "2.md",
          "link": "/reviews/aaa/2"
      }
      ]
    },
    {
      "text": "bbb",
      "collapsed": false,
      "items": [
      {
          "text": "1.md",
          "link": "/reviews/bbb/1"
      }
      ]
    }
]
};

[*]而后,在我们的config.mts中引用即可import { defineConfig } from 'vitepress'
import { sidebarConfig } from './sidebar.generated.js';

// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "coding",
description: "code review helper",
themeConfig: {
    // https://vitepress.dev/reference/default-theme-config
    nav: [
      { text: 'Home', link: '/' },
      { text: 'Reviews', link: '/reviews' }
    ],

    sidebar: sidebarConfig,
},
async buildEnd() {
    const { writeSidebarConfig } = await import('./utils/generateSidebar.js');
    await writeSidebarConfig();
}
})

监听文件变化



[*]在utils/generateSidebar.ts最后添加这一段,监控该目录下的文件变化,当有变化时,会主动调用writeSidebarConfig重新天生侧边栏内容// 开发模式文件监听
if (process.env.NODE_ENV === 'development' || process.argv.includes('--watch')) {
    const watcher = chokidar.watch('doc/reviews/**/*.md', {
      ignored: /(^|[/\\])\../,
      persistent: true
    });

    watcher
      .on('add', () => writeSidebarConfig())
      .on('unlink', () => writeSidebarConfig());

    process.stdin.resume();
}

使用pm2管理监听进程



[*]发起在linux下使用,windows下有问题
[*]安装npm install -D pm2

[*]新建ecosystem.config.jsmodule.exports = {
    apps: [
      {
            name: 'vitepress',
            script: 'npm',
            args: 'run docs:dev',
            watch: ['doc/.vitepress/sidebar.generated.ts']
      },
      {
            name: 'sidebar-watcher',
            script: 'npm',
            args: 'run dev:sidebar',
            watch: false
      }
    ]
};

[*]修改package.json{
"scripts": {
    "start": "pm2 start eco.config.js",
    "stop": "pm2 stop eco.config.js",
    "docs:dev": "vitepress dev doc",
    "docs:build": "vitepress build doc",
    "docs:preview": "vitepress preview doc",
    "docs:sidebar": "tsx doc/.vitepress/utils/generateSidebar.ts --watch"
},
"devDependencies": {
    // ...
}
}

[*]运行npm run start


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【VitePress】新增md文件后主动更新侧边栏导航