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

news2025/4/15 13:00:27

目录

  • 说在前面
  • 先看效果
  • 代码结构
  • 详细说明
    • 侧边栏格式
    • utils
    • 监听文件变化
    • 使用pm2管理监听进程

说在前面

  • 操作系统:windows11
  • node版本:v18.19.0
  • npm版本:10.2.3
  • vitepress版本:1.6.3
  • 完整代码:github

先看效果

  • 模板用的就是官方主题
    在这里插入图片描述
    在这里插入图片描述

代码结构

详细说明

侧边栏格式

  • 通常,侧边栏定义在config.mts
    export default {
      themeConfig: {
        sidebar: [
          {
            text: 'Guide',
            items: [
              { text: 'Introduction', link: '/introduction' },
              { text: 'Getting Started', link: '/getting-started' },
              ...
            ]
          }
        ]
      }
    }
    
    例如上述代码定义了这样子的侧边栏:
    在这里插入图片描述
  • 而现在,我们需要根据目录内容,自动生成一个侧边栏

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] || '0');
                    const numB = parseInt(b.text.match(/\d+/)?.[0] || '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.js
    module.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
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker部署scylladb

创建存储数据的目录和配置目录 mkdir -p /root/docker/scylla/data/data /root/docker/scylla/data/commitlog /root/docker/scylla/data/hints /root/docker/scylla/data/view_hints /root/docker/scylla/conf快速启动拷贝配置文件 docker run -d \--name scylla \scylladb/…

Android 16应用适配指南

Android 16版本特性介绍 https://developer.android.com/about/versions/16?hlzh-cn Android 16 所有功能和 API 概览 https://developer.android.com/about/versions/16/features?hlzh-cn#language-switching Android 16 发布时间 Android 16 适配指南 Google开发平台&…

2.2goweb解析http请求信息

Go语言的net/http包提供了一些列用于表示HTTP报文的解构。我们可以使用它处理请求和发送响应。其中request结构体代表了客户端发生的请求报文。 核心字段获取方法 1. 请求行信息 通过 http.Request 结构体获取&#xff1a; func handler(w http.ResponseWriter, r *http.Req…

本地部署大模型(ollama模式)

分享记录一下本地部署大模型步骤。 大模型应用部署可以选择 ollama 或者 LM Studio。本文介绍ollama本地部署 ollama官网为&#xff1a;https://ollama.com/ 进入官网&#xff0c;下载ollama。 ollama是一个模型管理工具和平台&#xff0c;它提供了很多国内外常见的模型&…

redis之缓存击穿

一、前言 本期我们聊一下缓存击穿&#xff0c;其实缓存击穿和缓存穿透很相似&#xff0c;区别就是&#xff0c;缓存穿透是一些黑客故意请求压根不存在的数据从而达到拖垮系统的目的&#xff0c;是恶意的&#xff0c;有针对性的。缓存击穿的情况是&#xff0c;数据确实存在&…

txt、Csv、Excel、JSON、SQL文件读取(Python)

txt、Csv、Excel、JSON、SQL文件读取&#xff08;Python&#xff09; txt文件读写 创建一个txt文件 fopen(rtext.txt,r,encodingutf-8) sf.read() f.close() print(s)open( )是打开文件的方法 text.txt’文件名 在同一个文件夹下所以可以省略路径 如果不在同一个文件夹下 ‘…

【NLP解析】多头注意力+掩码机制+位置编码:Transformer三大核心技术详解

目录 多头注意力&#xff1a;让模型化身“多面手” 技术细节&#xff1a;多头注意力如何计算&#xff1f; 实际应用&#xff1a;多头注意力在Transformer中的威力 为什么说多头是“非线性组合”&#xff1f; 实验对比&#xff1a;多头 vs 单头 进阶思考&#xff1a;如何设计更高…

Downlink Sensing in 5G-Advanced and 6G: SIB1-assisted SSB Approach

摘要——本文研究了利用现有5G NR信号进行网络侧集成感知与通信&#xff08;ISAC&#xff09;的潜力。通常&#xff0c;由于其频繁的周期性可用性和波束扫描特性&#xff0c;同步信号块&#xff08;SSB&#xff09;是适合用于下行感知的候选信号。然而&#xff0c;正如本文所示…

设计模式 Day 8:策略模式(Strategy Pattern)完整讲解与实战应用

&#x1f504; 前情回顾&#xff1a;Day 7 重点回顾 在 Day 7 中&#xff0c;我们彻底讲透了观察者模式&#xff1a; 它是典型的行为型模式&#xff0c;核心理念是“一变多知”&#xff0c;当一个对象状态变化时&#xff0c;自动通知所有订阅者。 我们通过 RxCpp 实现了工业…

ONVIF/RTSP/RTMP协议EasyCVR视频汇聚平台RTMP协议配置全攻略 | 直播推流实战教程

在现代化的视频管理和应急指挥系统中&#xff0c;RTMP协议作为一种高效的视频流传输方式&#xff0c;正变得越来越重要。无论是安防监控、应急指挥&#xff0c;还是物联网视频融合&#xff0c;掌握RTMP协议的接入和配置方法&#xff0c;都是提升系统性能和效率的关键一步。 今天…

《微服务与事件驱动架构》读书分享

《微服务与事件驱动架构》读书分享 Building Event-Driver Microservices 英文原版由 OReilly Media, Inc. 出版&#xff0c;2020 作者&#xff1a;[加] 亚当 • 贝勒马尔 译者&#xff1a;温正东 作者简介&#xff1a; 这本书由亚当贝勒马尔&#xff08;Adam Bellemare…

每日一题(小白)暴力娱乐篇26

我们先直接尝试暴力循环四轮看能不能得到答案&#xff0c;条件&#xff1a;四个数的平方相加等于这个数 ①接收答案result ②循环四轮i&#xff0c;j&#xff0c;k&#xff0c;l ③如果i*ij*jk*kl*lresult ④按照要求的格式输出这四个数字 代码如下&#x1f447; public s…

如何使用AI辅助开发R语言

R语言是一种用于统计计算和图形生成的编程语言和软件环境&#xff0c;很多学术研究和数据分析的科学家和统计学家更青睐于它。但对与没有编程基础的初学者而言&#xff0c;R语言也是有一定使用难度的。不过现在有了通义灵码辅助编写R语言代码&#xff0c;我们完全可以用自然语言…

Git版本管理系列:(三)远程仓库

目录 与远程仓库平台(github\gitee等)建立连接本地仓库关联远程仓库本地仓库内容推送远程仓库&#xff1a;PUSH将远程仓库的更新拉取到本地:PULL语法总结 与远程仓库平台(github\gitee等)建立连接 远程仓库平台相当于一个网盘&#xff0c;我们可以把自己的代码上传上去。就像网…

React Hooks: useRef,useCallback,useMemo用法详解

1. useRef&#xff08;保存引用值&#xff09; useRef 通常用于保存“不会参与 UI 渲染&#xff0c;但生命周期要长”的对象引用&#xff0c;比如获取 DOM、保存定时器 ID、WebSocket等。 新建useRef.js组件&#xff0c;写入代码&#xff1a; import React, { useRef, useSt…

[wifi SAE]wpa3-personal

SAE &#xff1a;Simultaneous Authentication of Equals&#xff08;同等同时认证&#xff09; wpa2和wpa3之间最大的区别是认证过程的区别 WPA2不安全性 1.sta和ap预置psk(AP密码) 2.四次握手生成ptk用于后续数据加密的密钥 ptk计算基于psk、双方随机数&#xff1b; 双方都产…

电路方案分析(二十)TPS63xxx系列DC/DC电源EMI PCB设计方案

tips&#xff1a;资料来自网络&#xff0c;仅供学习使用。[TOC](TPS63xxx系列DC/DC电源EMI PCB设计方案) 1.概述 通过TPS63xxx系列DC/DC电源模块来分析降低直流/直流降压/升压转换器辐射 EMI 的来源以及相关PCB设计。 下面都以最常用的TPS63070为例说明&#xff1a; 典型应用…

Java 大厂面试题 -- JVM 深度剖析:解锁大厂 Offe 的核心密钥

最近佳作推荐&#xff1a; Java大厂面试高频考点&#xff5c;分布式系统JVM优化实战全解析&#xff08;附真题&#xff09;&#xff08;New&#xff09; Java大厂面试题 – JVM 优化进阶之路&#xff1a;从原理到实战的深度剖析&#xff08;2&#xff09;&#xff08;New&#…

目标追踪Hyperspectral Adapter for Object Tracking based on Hyperspectral Video

论文作者&#xff1a;Long Gao,Yunhe Zhang,Langkun Chen,Yan Jiang,Weiying Xie,Yunsong Li 作者单位&#xff1a;Xidian University;the University of Sheffield 论文链接&#xff1a;http://arxiv.org/abs/2503.22199v1 内容简介&#xff1a; 1&#xff09;方向&#x…

深度剖析SSD多段L2P表查找加速技术

在固态硬盘(SSD)控制器中,逻辑块地址(LBA)需要通过映射表(L2P Table)映射到NAND闪存的物理地址(PA)。随着SSD容量的增长,L2P表的大小也随之增加,这给查找操作带来了性能挑战。 在SSD控制器中,LBA需借助L2P表映射为NAND物理地址。映射表最小规模为 (O(n * \lg (n)))…