- 由于不需要后端响应,所以应该是预渲染而不是服务端渲染
介绍
- VuePress 由两部分组成:
- 第一部分是一个极简静态网站生成器,它包含由 Vue 驱动的主题系统和插件 API(主题系统,应该是符合某些标准的组件库?插件?)
- 另一个部分是为书写技术文档而优化的默认主题,它的诞生初衷是为了支持 Vue 及其子项目的文档需求
Features
- 内置的 Markdown 拓展,在 Markdown 中 使用 Vue
- Vue驱动的自定义主题系统,默认主题,博客主题
- Plugin
为什么不是...?
- Hexo 主题系统太过于静态以及过度地依赖纯字符串,而我们十分希望能够好好地利用 Vue 来处理我们的布局和交互
- GitBook 当文件很多时,每次编辑后的重新加载时间长得令人无法忍受
——————————————————————————————————————————————————————————————————————
快速上手
- 如果你的现有项目依赖了 webpack 3.x,我们推荐使用 Yarn 而不是 npm 来安装 VuePress。因为在这种情形下,npm 会生成错误的依赖树。
- 指定依赖的文档目录
{
"scripts": {
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
}
}
——————————————————————————————————————————————————————————————————————
目录结构
- VuePress 遵循 “约定优于配置” 的原则
├── docs
│ ├── .vuepress (可选的) 用于存放全局的配置、组件、静态资源等。
│ │ ├── components (可选的) 该目录中的 Vue 组件将会被自动注册为全局组件。
│ │ ├── theme (可选的) 用于存放本地主题。(多个组件的组合?)
│ │ │ └── Layout.vue
│ │ ├── public (可选的) 静态资源目录。
│ │ ├── styles (可选的) 用于存放样式相关的文件。
│ │ │ ├── index.styl 将会被自动应用的全局样式文件,会生成在最终的 CSS 文件结尾,具有比默认样式更高的优先级。
│ │ │ └── palette.styl 用于重写默认颜色常量,或者设置新的 stylus 颜色常量。
│ │ ├── templates (可选的, 谨慎配置) 存储 HTML 模板文件。(模板?vue根节点?)
│ │ │ ├── dev.html 用于开发环境的 HTML 模板文件。
│ │ │ └── ssr.html 构建时基于 Vue SSR(服务端渲染) 的 HTML 模板文件。(为什么要有不同?)
│ │ ├── config.js (可选的) 配置文件的入口文件,也可以是 YML 或 toml。
│ │ └── enhanceApp.js (可选的) 客户端应用的增强。?
│ │
│ ├── README.md 请留意目录名的大写
│ ├── guide
│ │ └── README.md
│ └── config.md
│
└── package.json
默认的页面路由
- 文件的相对路径对应的页面路由地址
- /README.md 对应 /
- /guide/README.md 对应 /guide/
- /config.md 对应 /config.html
——————————————————————————————————————————————————————————————————————
基本配置
配置文件
- .vuepress/config.js 不支持热更新,不依赖于特定主题,主题和插件可以提供额外的配置项
module.exports = {
title: 'Hello VuePress',
description: 'Just playing around'
}
- VuePress 内置了基于 headers 的搜索 —— 它会自动为所有页面的标题、h2 和 h3 构建起一个简单的搜索索引。
主题配置
- 一个 VuePress 主题应该负责整个网站的布局和交互细节。
应用级别的配置
- 通过创建一个 .vuepress/enhanceApp.js 文件来做一些应用级别的配置,当该文件存在的时候,会被导入到应用内部。
- enhanceApp.js 应该 export default 一个钩子函数,并接受一个包含了一些应用级别属性的对象作为参数。你可以使用这个钩子来安装一些附加的 Vue 插件、注册全局组件,或者增加额外的路由钩子等
// 使用异步函数也是可以的
export default ({
Vue, // VuePress 正在使用的 Vue 构造函数
options, // 附加到根实例的一些选项
router, // 当前应用的路由实例
siteData, // 站点元数据?
isServer // 当前应用配置是处于 服务端渲染 或 客户端
}) => {
// ...做一些其他的应用级别的优化
}
——————————————————————————————————————————————————————————————————————
静态资源
相对路径
- 所有的 Markdown 文件都会被 webpack 编译成 Vue 组件,因此你可以,并且应该更倾向于使用相对路径(Relative URLs)来引用所有的静态资源。在 *.vue 文件的模板中一样可以工作,图片将会被 url-loader 和 file-loader 处理,在运行生成静态文件的构建任务时,文件会被复制到正确的位置。

- 使用 ~ 前缀来明确地指出这是一个 webpack 的模块请求,这将允许你通过 webpack 别名来引用文件或者 npm 的依赖


- Webpack 的别名可以通过 .vuepress/config.js 中 configureWebpack 来配置
module.exports = {
configureWebpack: {
resolve: {
alias: {
'@alias': 'path/to/some/dir'
}
}
}
}
公共文件
- 可能需要提供一个静态资源,但是它们并不直接被你的任何一个 markdown 文件或者主题组件引用 —— 举例来说,favicons 和 PWA 的图标,在这种情形下,你可以将它们放在 .vuepress/public 中, 它们最终会被复制到生成的静态文件夹中。
- 注释:如果 URL 是一个绝对路径 (例如 /images/foo.png),它将会被保留不变。
基础路径
- 如果你的网站会被部署到一个非根路径,你将需要在 .vuepress/config.js 中设置 base,举例来说,如果你打算将你的网站部署到 https://foo.github.io/bar/,那么 base 的值就应该被设置为 "/bar/" (应当总是以斜杠开始,并以斜杠结束)。
- 有了基础路径(Base URL),如果你希望引用一张放在 .vuepress/public 中的图片,你需要使用这样路径:/bar/image.png
- VuePress 提供了内置的一个 helper $withBase(它被注入到了 Vue 的原型上),可以帮助你生成正确的路径:
<img :src="$withBase('/foo.png')" alt="foo">
- 不仅可以在你的 Vue 组件中使用上述的语法,在 Markdown 文件中亦是如此。
- 一个 base 路径一旦被设置,它将会自动地作为前缀插入到 .vuepress/config.js 中所有以 / 开始的资源路径中。
——————————————————————————————————————————————————————————————————————
Markdown 拓展
Header Anchors 锚点
- 所有的标题将会自动地应用 anchor 链接,anchor 的渲染可以通过 markdown.anchor 来配置。
链接
内部链接
- 网站内部的链接,将会被转换成 <router-link> 用于 SPA 导航
- 站内的每一个文件夹下的 README.md 或者 index.md 文件都会被自动编译为 index.html
.
├─ README.md
├─ foo
│ ├─ README.md
│ ├─ one.md
│ └─ two.md
└─ bar
├─ README.md
├─ three.md
└─ four.md
[Home](/) <!-- 跳转到根部的 README.md -->
[foo](/foo/) <!-- 跳转到 foo 文件夹的 index.html -->
[foo heading](./#heading) <!-- 跳转到 foo/index.html 的特定标题位置 -->
[bar - three](../bar/three.md) <!-- 具体文件可以使用 .md 结尾(推荐) -->
[bar - four](../bar/four.html) <!-- 也可以用 .html -->
链接的重定向
- 如果一个链接 /foo 找不到,VuePress 会自行寻找一个可用的 /foo/ 或 /foo.html
- 注释:静态文件服务器当 /foo 无法返回资源时,会请求 /foo/ 地址。 /foo/ 等价于 /foo/index.html
- 注释:vue-router 的路由匹配默认会把 /foo 和 /foo/ 匹配到同一组件
- 注释:VuePress 必须实现 build 后文档分布和 url 相匹配,因为它会为每个路由进行预渲染生成静态文件,在客户端通过 url 要能找到对应的资源
- 注释:所以 markdown 文件中的跳转路径,是文件的实际路径,和它 build 后的路径或 url 路径无关。
- 注释:这里的链接重定向是指 VuePress 中的 vue-router 支持默认的匹配方式(即 /foo 和 /foo/ 匹配同一组件),同时支持在组件加载失败时跳转到 /foo.html 的操作(重新加载 document) - 借助这种特性,我们可以通过官方插件 vuepress-plugin-clean-urls 定制你的网站路径
- 无论是否使用了 permalink 和 clean-urls 插件,你的相对路径都应该依赖于当前的文件结构来定义。
外部链接
- 外部的链接将会被自动地设置为 target="_blank" rel="noopener noreferrer"
- noopener:指示浏览器打开链接而不授予新的浏览上下文对打开它的文档的访问权限-通过在打开的窗口中不设置Window.opener属性(返回null)
- noreferrer:阻止浏览器导航到另一个页面时,通过Referer:HTTP header将该页面地址或任何其他值作为Referrer发送。 - 可以自定义通过配置 config.markdown.externalLinks 来自定义外部链接的特性
Front Matter
- VuePress 提供了对 YAML front matter 开箱即用的支持。这些数据可以在当前 markdown 的正文,或者是任意的自定义或主题组件中使用。
- 注释:YAML front matter:在字符串前面解析 yaml 或 json,返回一个对象
- 注释:YAML:一种标记语言 - 注释:vuepress dev 添加 YAML 不支持热更新
---
title: Blogging Like a Hacker
lang: en-US
---
GitHub 风格的表格
:-------------:
th d 的 text-align:center-----:
th d 的 text-align:right
| Tables | Are | Cool |
| ------------- |:-------------:| -----:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
Emoji 表情
目录
- 目录(Table of Contents)的渲染可以通过 markdown.toc 选项来配置
- 注释:例子中渲染位目录 ul>li 列表
[[toc]]
自定义容器
- 注释:例子中渲染为含有标题的色块,有4种样式
- tip:绿色提示色块
- warning:黄色警告色块
- danger:红色危险色块
- details:灰色可展开色块
::: tip
这是一个提示
:::
::: warning
这是一个警告
:::
::: danger
这是一个危险警告
:::
::: details
这是一个详情块,在 IE / Edge 中不生效
:::
- 可以自定义块中的标题:
::: danger STOP
危险区域,禁止通行
:::
::: details 点击查看代码
这是一段代码
:::
- 注释:可以通过插件 vuepress-plugin-container 插件注册自定义色块
代码块中的语法高亮
- VuePress 使用了 Prism 来为 markdown 中的代码块实现语法高亮。Prism 支持大量的编程语言,你需要做的只是在代码块的开始倒勾中附加一个有效的语言别名:
``` js
export default {
name: 'MyComponent',
// ...
}
```
- 在 Prism 的网站上查看 合法的语言列表
代码块中的行高亮
- 注释:语法高亮依然会有,只是某一行背景有特殊样式
``` js {4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
- 除了单行以外,你也可指定多行,行数区间,或是两者都指定。
- 行数区间: 例如 {5-8}, {3-10}, {10-17}
- 多个单行: 例如 {4,7,9}
- 行数区间与多个单行: 例如 {4,7-13,16,23-27,40}
行号
- 可以通过配置来为每个代码块显示行号:
module.exports = {
markdown: {
lineNumbers: true
}
}
导入代码段
- 由于代码段的导入将在 webpack 编译之前执行,因此你无法使用 webpack 中的路径别名,此处的 @ 默认值是 process.cwd()
- 注释:process.cwd() 方法会返回 Node.js 进程的当前工作目录。(一般是 package.json 所在的目录)
// 语法
<<< @/filepath{highlightLines}
// 实例
<<< @/docs/cs.js{2}
<<< @/./docs/cs.js{2}
<<< @/../vue-press/docs/cs.js{2}
- 为了只导入对应部分的代码,可以在文件路径后方的 # 紧接着提供一个自定义的区域名称
export default{
czb:'123'
}
// #region snippet
const czb = 2
// #endregion snippet
<<< @/docs/cs.js#snippet{1}
// 只会输出如下代码块
const czb = 2
进阶配置
- VuePress 使用 markdown-it 来渲染 Markdown,上述大多数的拓展也都是通过自定义的插件实现的。插件是指 markdown-it 的插件?
- 可以通过 .vuepress/config.js 的 markdown 选项,来对当前的 markdown-it 实例做一些自定义的配置
module.exports = {
markdown: {
// markdown-it-anchor 的选项
anchor: { permalink: false },
// markdown-it-toc 的选项
toc: { includeLevel: [1, 2] },
extendMarkdown: md => {
// 使用更多的 markdown-it 插件!
md.use(require('markdown-it-xxx'))
}
}
}
——————————————————————————————————————————————————————————————————————
在 Markdown 中 使用 Vue
浏览器的 API 访问限制
-
所有的 Vue 相关代码都应当遵循 编写通用代码 的要求。简而言之,请确保只在 beforeMount 或者 mounted 访问浏览器 / DOM 的 API。
-
由于没有动态更新,所有的生命周期钩子函数中,只有 beforeCreate 和 created 会在服务器端渲染 (SSR) 过程中被调用。
-
应该避免在 beforeCreate 和 created 生命周期时产生全局副作用的代码,例如在其中使用 setInterval 设置 timer。在纯客户端 (client-side only) 的代码中,我们可以设置一个 timer,然后在 beforeDestroy 或 destroyed 生命周期时将其销毁。但是,由于在 SSR 期间并不会调用销毁钩子函数,所以 timer 将永远保留下来。
-
对于共享于服务器和客户端,但用于不同平台 API 的任务(task),建议将平台特定实现包含在通用 API 中,或者使用为你执行此操作的 library。例如,axios 是一个 HTTP 客户端,可以向服务器和客户端都暴露相同的 API。
-
大多数自定义指令直接操作 DOM,因此会在服务器端渲染 (SSR) 过程中导致错误。有两种方法可以解决这个问题:
- 推荐使用组件作为抽象机制,并运行在「虚拟 DOM 层级(Virtual-DOM level)」(例如,使用渲染函数(render function))。
- 如果你有一个自定义指令,但是不是很容易替换为组件,则可以在创建服务器 renderer 时,使用 directives 选项所提供"服务器端版本(server-side version)"。 -
如果你正在使用,或者需要展示一个对于 SSR 不怎么友好的组件(比如包含了自定义指令),你可以将它们包裹在内置的 <ClientOnly> 组件中
<ClientOnly>
<NonSSRFriendlyComponent/>
</ClientOnly>
- 这并不能解决一些组件或库在导入时就试图访问浏览器 API 的问题 —— 如果需要使用这样的组件或库,你需要在合适的生命周期钩子中动态导入它们
<template>
<component v-if="dynamicComponent" :is="dynamicComponent"></component>
</template>
<script>
export default {
data() {
return {
dynamicComponent: null
}
},
mounted () {
import('./lib-that-access-window-on-import').then(module => {
this.dynamicComponent = module.default
})
}
}
</script>
模板语法
插值
- 每一个 Markdown 文件将首先被编译成 HTML,接着作为一个 Vue 组件传入 vue-loader,这意味着你可以在文本中使用 Vue 风格的插值:
{{ 1 + 1 }}
# {{ 1 + 1 }}
指令
- 同样地,也可以使用指令:
<span v-for="i in 3">{{ i }} </span>
访问网站以及页面的数据
- 编译后的组件没有私有数据,但可以访问 网站的元数据
- 整个网站以及特定页面的元数据将分别暴露为 this.$site 和 this.$page 属性,它们将会被注入到每一个当前应用的组件中。
- $site 中 title, description 和 base 会从 .vuepress/config.js 中对应的的字段复制过来
{
"title": "VuePress",
"description": "Vue 驱动的静态网站生成器",
"base": "/",
"pages": [
{
"lastUpdated": 1524027677000,
"path": "/",
"title": "VuePress",
"frontmatter": {}
},
...
]
}
- pages 是一个包含了每个页面元数据对象的数据,包括它的路径、页面标题(明确地通过 YAML front matter 指定,或者通过该页面的第一个标题取到),以及所有源文件中的 YAML front matter 的数据。
{
"lastUpdated": 1524847549000,
"path": "/custom-themes.html",
"title": "自定义主题",
"headers": [/* ... */],
"frontmatter": {}
}
- 如果用户在 .vuepress/config.js 配置了 themeConfig,你将可以通过 $site.themeConfig 访问到它。如此一来,你可以通过它来对用户开放一些自定义主题的配置 —— 比如指定目录或者页面的顺序,你也可以结合 $site.pages 来动态地构建导航链接。
- 作为 Vue Router API 的一部分,this.$route 和 this.$router 同样可以使用。
- lastUpdated 是这个文件最后一次 git 提交的 UNIX 时间戳
Escaping
- 默认情况下,块级 (block) 的代码块将会被自动包裹在 v-pre 中。
- 注释:块级代码应该是的 html 标签
- 如果你想要在内联 (inline) 的代码块或者普通文本中显示原始的大括号,或者一些 Vue 特定的语法,你需要使用自定义容器 v-pre 来包裹
::: v-pre
`{{ This will be displayed as-is }}`
<div>{{ This will be displayed as-is }}</div>
:::
使用组件
- 所有在 .vuepress/components 中找到的 *.vue 文件将会自动地被注册为全局的异步组件
- 可以直接使用这些组件在任意的 Markdown 文件中(组件名是通过文件名取到的)
- 请确保一个自定义组件的名字包含连接符或者是 PascalCase,否则,它将会被视为一个内联元素,并被包裹在一个 <p> 标签中,这将会导致 HTML 渲染紊乱,因为 HTML 标准规定, <p> 标签中不允许放置任何块级元素。
<demo-1/>
<OtherComponent/>
<Foo-Bar/>
在标题中使用组件
- 可以在标题中使用 Vue 组件,但是请留意以下两种方式的不同
# text <Tag/> // 实际渲染了组件 Tag
# text `<Tag/>` // 编译为 <h1>text <code><Tag/></code></h1>,实际不是两种方式,`...` 在 Markdown 中被编译为 <code> 标签包裹的 html
使用预处理器
- VuePress 对以下预处理器已经内置相关的 webpack 配置:sass、scss、less、stylus 和 pug。要使用它们你只需要在项目中安装对应的依赖即可。
yarn add -D sass-loader node-sass
- 注释:pug 模板引擎 - 可以在 Markdown 或是组件中使用如下代码
<style lang="sass">
.title
font-size: 20px
</style>
<template lang="pug">
- 使用 config.configureWebpack 拓展内部的 Webpack 配置
脚本和样式提升
- 直接在 Markdown 文件中使用原生的 <script> 或者 <style> 标签,它们将会从编译后的 HTML 文件中提取出来,并作为生成的 Vue 单文件组件的 <script> 和 <style> 标签。
内置的组件
OutboundLink
- 注释:一个图标
- 用来表明当前是一个外部链接。在 VuePress 中这个组件会紧跟在每一个外部链接后面。
ClientOnly
- 该组件内的子组件只在客户端渲染
Content
- Markdown 文件是元数据(页面内容、配置等)的提供者,而布局组件负责消费他们。我们可以通过 frontmatter 来定义一些普通数据类型的元数据,但对于 Markdown / HTML 这种涉及到编译前后差异的复杂元数据,frontmatter 却无能能力
- 可以通过下述的语法来定义一个具名 Markdown 插槽:在布局组件中利用 Content 组件来使用该插槽
::: slot name
:::
<Content slot-key="name"/>
- 默认情况下,一个 Markdown 文件中的普通内容将会成为 Markdown 插槽的默认内容,你可以直接使用 Content 组件来访问它
- 和 Vue 本身提供的 slot 机制不太相同,每个 Content 分发的内容都会被一个 div 所包裹,其 class 是 content 和 slot 的名字。
- 请确保所定义的 slot 的唯一性。
- Props:
- pageKey - string, 要渲染的 page 的 hash key, 默认值是当前页面的 key.
- slotKey - string, 页面的 markdown slot 的 key. 默认值是 default slot.
Badge
- 可以在标题中,使用这个组件来为某些 API 添加一些状态
- 注释:就是一个色块组件,用哪都行
- Props:
- text - string
- type - string, 可选值: "tip"|"warning"|"error",默认值是: "tip"
- vertical - string, 可选值: "top"|"middle",默认值是: "top"
### Badge <Badge text="beta" type="warning"/> <Badge text="默认主题"/>
——————————————————————————————————————————————————————————————————————
多语言支持
站点多语言配置
- 要启用 VuePress 的多语言支持,首先需要使用如下的文件结构:
docs
├─ README.md
├─ foo.md
├─ nested
│ └─ README.md
└─ zh
├─ README.md
├─ foo.md
└─ nested
└─ README.md
- 然后,在 .vuepress/config.js 中提供 locales 选项:
module.exports = {
locales: {
// 键名是该语言所属的子路径
// 作为特例,默认语言可以使用 '/' 作为其路径。
'/': {
lang: 'en-US', // 将会被设置为 <html> 的 lang 属性
title: 'VuePress',
description: 'Vue-powered Static Site Generator'
},
'/zh/': {
lang: 'zh-CN',
title: 'VuePress',
description: 'Vue 驱动的静态网站生成器'
}
}
}
- 如果一个语言没有声明 title 或者 description,VuePress 将会尝试使用配置顶层的对应值。如果每个语言都声明了 title 和 description,则顶层的这两个值可以被省略
默认主题多语言配置
- 默认主题也内置了多语言支持,可以通过 themeConfig.locales 来配置。该选项接受同样的 { path: config } 格式的值。每个语言除了可以配置一些站点中用到的文字之外,还可以拥有自己的 导航栏 和 侧边栏 配置:
module.exports = {
locales: { /* ... */ },
themeConfig: {
locales: {
'/': {
selectText: 'Languages',
label: 'English',
ariaLabel: 'Languages',
editLinkText: 'Edit this page on GitHub',
serviceWorker: {
updatePopup: {
message: "New content is available.",
buttonText: "Refresh"
}
},
algolia: {},
nav: [
{ text: 'Nested', link: '/nested/', ariaLabel: 'Nested' }
],
sidebar: {
'/': [/* ... */],
'/nested/': [/* ... */]
}
},
'/zh/': {
// 多语言下拉菜单的标题
selectText: '选择语言',
// 该语言在下拉菜单中的标签
label: '简体中文',
// 编辑链接文字
editLinkText: '在 GitHub 上编辑此页',
// Service Worker 的配置
serviceWorker: {
updatePopup: {
message: "发现新内容可用.",
buttonText: "刷新"
}
},
// 当前 locale 的 algolia docsearch 选项
algolia: {},
nav: [
{ text: '嵌套', link: '/zh/nested/' }
],
sidebar: {
'/zh/': [/* ... */],
'/zh/nested/': [/* ... */]
}
}
}
}
}