VuePress 目录结构详解:从 `.vuepress` 约定到默认页面路由规则
2026/9/20 5:28:52 网站建设 项目流程
  • 前端
  • 文档
  • SSR

【免费下载链接】vuepress

📝 Minimalistic Vue-powered static site generator

项目地址:https://gitcode.com/gh_mirrors/vu/vuepress
点击查看免费下载

VuePress 的核心设计理念是**“约定优于配置”**(Convention over Configuration):你只需按照一套固定的目录约定摆放文件,VuePress 的源码编译流程就会自动完成全局组件注册、主题加载、样式注入、页面扫描与路由生成。本篇基于本仓库packages/docs/docs/guide/directory-structure.md原文,结合@vuepress/core@vuepress/shared-utils的源码实现,逐层拆解.vuepress下每个目录/文件的真实作用与加载顺序,并解释“为什么README.md会路由到/config.md会路由到/config.html”。读完本文,你将能够从零搭建一个符合 VuePress 约定的文档项目,并在自定义模板、样式、组件与路由时知道该把文件放在哪里、以及背后的生效机制。

一、约定优于配置:推荐目录结构总览

VuePress 官方推荐的目录结构如下(原文完整摘录):

. ├── docs │ ├── .vuepress _(**可选**)_ │ │ ├── `components` _(**可选**)_ │ │ ├── `theme` _(**可选**)_ │ │ │ └── Layout.vue │ │ ├── `public` _(**可选**)_ │ │ ├── `styles` _(**可选**)_ │ │ │ ├── index.styl │ │ │ └── palette.styl │ │ ├── `templates` _(**可选, 谨慎配置**)_ │ │ │ ├── dev.html │ │ │ └── ssr.html │ │ ├── `config.js` _(**可选**)_ │ │ └── `enhanceApp.js` _(**可选**)_ │ │ │ ├── README.md │ ├── guide │ │ └── README.md │ └── config.md │ └── package.json

特别注意:目录名的大小写是敏感的。.vuepress必须小写,README.md必须大写。若写错大小写,VuePress 将无法识别对应目录或页面文件——这一点在@vuepress/core的路径解析中体现得淋漓尽致:所有约定路径都是通过path.resolve(sourceDir, '.vuepress')这类精确拼写来定位的(见 App.js)。

在这个结构中,docs是站点源码目录(即命令行中的targetDir),package.json位于项目根目录。从源码结构看,docs目录下除.vuepress之外的任意 Markdown / Vue 文件都会进入页面扫描流程(见下文第四节)。

二、.vuepress核心目录逐项拆解

.vuepress是 VuePress 的“配置中枢”,存放全局配置、组件、静态资源与主题。原文逐项说明了其用途,下面结合源码进一步展开每个条目背后的加载机制。

2.1components:自动注册为全局组件

docs/.vuepress/components中的 Vue 组件会被自动注册为全局组件,无需手动引入。其实现位于官方插件 plugin-register-components/index.js:插件会通过globby(['**/*.vue'])扫描该目录,然后生成一段形如Vue.component('name', () => import(path))的代码注入客户端。

组件名由fileToComponentName决定——文件路径中的/\会被替换为-(plugin-register-components/index.js),例如components/Foo/Bar.vue会注册为全局组件Foo-Bar

在核心层,App.js 的applyInternalPlugins()会以@vuepress/register-components插件注册三个组件扫描目录,按优先级排列为:

  1. docs/.vuepress/components(站点级)
  2. 当前主题的global-components目录
  3. 父主题(若存在)的global-components目录

这也是为什么默认主题自带 Badge.vue、CodeGroup.vue 等全局组件 可以直接在 Markdown 中使用的根本原因。

2.2theme:存放本地主题

docs/.vuepress/theme用于存放本地主题(Local Theme)。其加载优先级定义在 loadTheme.js 中:

  1. theme配置项指向的绝对路径存在,优先使用该路径;
  2. 否则检查docs/.vuepress/theme目录是否存在且非空,存在则作为本地主题;
  3. 否则把theme配置当作包名,从依赖中解析(如@vuepress/theme-default)。

主题目录内的Layout.vue是核心布局文件。从 theme-api/index.js 的实现看,主题会同时扫描主题根目录与layouts/子目录中的.vue文件作为命名布局;若找不到Layout.vue,会回退到内置的Layout.fallback.vue并打印警告;404.vue会被归一化为NotFound布局。

仓库中的测试用本地主题示例可参考mocks/vuepress-theme-parent 与mocks/vuepress-theme-child,分别演示了父主题与子主题的目录组织方式。

2.3styles/index.styl:自动应用的全局样式

docs/.vuepress/styles/index.styl自动应用的全局样式文件。从 internal-plugins/style/index.js 的ready()钩子可以看出,它会在构建阶段生成一个临时的style.styl,其内容结构为:

// Theme's Styles @import(".../theme/styles/index.styl") // User's Styles @import(".../.vuepress/styles/index.styl")

先引入主题样式,再引入你的样式,因此index.styl中的规则排在 CSS 文件末尾,具有比默认样式更高的优先级,可以直接覆盖主题样式。若存在父主题,父主题样式会再排在最前面。

另外,该插件还顺带检测了从 v1.0.0 起已被废弃的docs/.vuepress/override.styl,并提示改用styles/palette.styl(internal-plugins/style/index.js)。

2.4styles/palette.styl:颜色常量与 Stylus 变量

docs/.vuepress/styles/palette.styl用于重写默认颜色常量或定义新的 Stylus 颜色常量。其底层机制在 internal-plugins/palette/index.js 中:该插件会把核心库的 style/config.styl 通过stylus.import全局注入,同时生成临时palette.styl

// Theme's Palette @import(".../theme/styles/palette.styl") // User's Palette @import(".../.vuepress/styles/palette.styl")

用户自定义的 palette 永远排在主题 palette 之后,从而保证你的颜色常量可以覆盖主题与默认常量。如果你在 paletter 中定义了$accentColor之类的变量,主题样式文件可以直接引用——这正是默认主题 styles/config.styl 中大量使用变量的前提。

2.5public:静态资源目录

docs/.vuepress/public是静态资源目录,该目录下的文件会被原样拷贝/托管,不会被 VuePress 编译。开发服务器将它的绝对路径作为contentBase(dev/index.js),因此你可以通过/xxx.png这样的根路径直接访问其中的文件。更完整的静态资源用法(含base路径影响、<img>引用写法)可阅读 assets.md。

2.6templates:HTML 模板(危险区,谨慎配置)

templates存放两个 HTML 模板文件:

  • dev.html:开发环境的 HTML 模板;
  • ssr.html:构建时基于 Vue SSR 的 HTML 模板。

自定义这两个模板时必须小心。核心层的模板解析逻辑在 App.js 的resolveTemplates()中,其解析优先级为(以devTemplate为例):

  1. siteConfig.devTemplate配置项;
  2. docs/.vuepress/templates/dev.html约定文件;
  3. 主题入口文件的devTemplate配置;
  4. 核心库默认模板。

官方警告:自定义templates/ssr.htmltemplates/dev.html时,最好基于默认模板修改,否则可能导致构建失败。默认模板位于核心库 index.dev.html 与 index.ssr.html,二者非常精简,核心就是一个<div id="app"></div>挂载点,修改时请保留这个挂载点结构。

2.7config.js:配置文件入口

docs/.vuepress/config.js是配置文件的入口文件。原文指出它也可以是ymltoml;而实际源码 loadConfig.js 还额外支持config.ts。四者共存的解析优先级是:

  1. config.yml(或.yaml,经js-yaml解析);
  2. config.ts(经bundle-require打包后取mod.defaultmod);
  3. config.toml(经toml解析,head数组会被重排为 VuePress 约定的格式,见 loadConfig.js);
  4. config.js(通过require直接加载)。

如果config.js导出一个函数,该函数会收到应用上下文并被调用,返回值作为站点配置(App.js)。全部配置项的完整说明见 config/README.md;TypeScript 写法见 typescript-as-config.md。

2.8enhanceApp.js:应用级增强

docs/.vuepress/enhanceApp.js用于在应用层面做增强,例如注册全局组件、混入、路由守卫等。其加载逻辑在 internal-plugins/enhanceApp.js 中:它会按顺序收集三个文件——

  1. docs/.vuepress/enhanceApp.js(站点级);
  2. 父主题的enhanceApp.js(若存在);
  3. 主题的enhanceApp.js

默认导出的函数签名是({ Vue, options, router, siteData }) => {},其中Vue是 Vue 构造器、options是根实例选项、router是路由实例、siteData是站点元数据。更完整的用法参见 using-vue.md。

三、theme目录与默认主题的关系

需要区分两个概念:本地主题目录docs/.vuepress/theme)与官方默认主题包@vuepress/theme-default,源码位于 theme-default)。

  • 如果你没有配置theme,且没有本地主题目录,VuePress 会使用依赖中解析到的默认主题@vuepress/theme-default
  • 如果你想完全自定义站点外观,可以在docs/.vuepress/theme下创建Layout.vue搭建本地主题;
  • 默认主题的布局与组件全部位于 theme-default/layouts 与 theme-default/components,可作为自定义主题时的参考模板。

关于主题的编写、继承(extend)与使用方式,分别见 writing-a-theme.md、inheritance.md 与 using-a-theme.md。

四、页面源文件:哪些文件会变成页面

页面扫描发生在 App.js 的resolvePages()中:VuePress 以targetDir(即示例中的docs)为根,用globby匹配**/*.md**/*.vue文件(可通过siteConfig.patterns覆盖),并始终排除.vuepressnode_modules目录。若配置了dest且输出目录位于源目录内,也会被排除,避免构建产物被当作页面源。

这意味着docs下除.vuepress外的每个 Markdown 文件都对应一个页面;而.vue文件会被当作布局组件处理(Page.js 中会给 Vue SFC 自动附加layout属性)。

五、默认页面路由:从相对路径到 URL 的映射规则

5.1 添加 npm scripts

docs目录作为targetDir后,在项目根目录的package.json中添加如下脚本(原文示例,可原样使用):

{ "scripts": { "dev": "vuepress dev docs", "build": "vuepress build docs" } }
  • vuepress dev docs启动带热更新的开发服务器;
  • vuepress build docs生成静态站点,默认输出到docs/.vuepress/dist(见 App.js,也可通过dest配置或-d参数覆盖)。

5.2 默认路由映射表

对于前文给出的目录结构,默认页面路由如下(原文完整表格):

文件的相对路径(相对docs页面路由地址
/README.md/
/guide/README.md/guide/
/config.md/config.html

5.3 规则背后的源码实现

这三条映射不是“魔法”,而是@vuepress/shared-utils中 fileToPath.ts 的确定性算法:

  • README.md/isIndexFile()会命中indexreadme的约定(正则/(^|.*\/)(index|readme)\.(md|vue)$/i,见 isIndexFile.ts),于是把README.md替换为所在目录路径。docs根目录的README.md位于根层级,因此映射为/
  • guide/README.md/guide/:同样是 index 文件规则,映射为所在目录guide的路径/guide/
  • config.md/config.html:普通 Markdown 文件会去掉.md扩展名并追加.html,得到/config.html

注意大小写:READMEindex的匹配是大小写不敏感的(正则末尾的i标志),因此readme.mdINDEX.md也会被视为首页文件。

页面路径计算发生在 Page.js 的构造函数中(regularPath = encodeURI(fileToPath(relative))),随后由@vuepress/internal-routes插件生成 Vue Router 路由表(routes.js)。生成的每条路由还附带几条自动重定向规则:

  • /结尾的路径自动补充xxx/index.htmlxxx/的重定向,保证直接访问guide/index.html也能到达/guide/
  • 对 URL 编码差异路径(decodeURIComponent后不同)生成重定向;
  • 未匹配到任何页面的路径统一落入*通配路由(404 页面)。

仓库的测试夹具也印证了这一约定:核心层的 prepare/fixtures/docs 目录下同时存在README.mdalpha.mdexcerpt.md等文件,配合Page.spec.js的快照验证了路径映射结果。

5.4 自定义路由:permalink与 frontmatter

默认路由规则可以通过每个页面的 frontmatterpermalink字段覆盖,例如在config.md顶部声明permalink: /settings/即可得到自定义路径;也可以在站点配置中通过permalink模板(如/:year/:month/:day/:slug)统一设置。相关细节见 permalinks.md 与 frontmatter.md。

六、与其他文档的衔接

本指南聚焦目录约定与路由映射,与之配套的官方文档还包括:

  • Config 配置:.vuepress/config.js的全部配置项;
  • Theme 主题:主题体系与布局约定;
  • Default Theme Config:默认主题的可配置项;
  • Command-line Interface:vuepress dev/build的全部 CLI 参数(含targetDir-d--temp等);
  • Getting Started:从安装到运行的最小实践路径。

小结

VuePress 的目录结构本质上是一套“文件即配置”的声明式系统:.vuepress/components决定全局组件、styles/index.stylstyles/palette.styl决定样式覆盖顺序、templates决定 HTML 骨架、enhanceApp.js决定应用增强、config.js(或其 yml/toml/ts 变体)决定全局行为,而docs下的 Markdown 文件则按fileToPath的规则自动生成页面路由。理解这些约定的加载顺序与优先级,是自定义主题、调整样式与构建复杂文档站点的第一步。

  • 前端
  • 文档
  • SSR

【免费下载链接】vuepress

📝 Minimalistic Vue-powered static site generator

项目地址:https://gitcode.com/gh_mirrors/vu/vuepress
点击查看免费下载

相关推荐

上一篇:LifeOS 中的 AgentRace 工作流:在 cmux 竞技场中用多 Agent 并行竞赛定位并修复疑难 Bug
下一篇:coc-clangd与LLVM生态整合:打造完整的C++开发工具链

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询