From 8bbc5f30c7d2458ae2e5cb3f67709350e84a179c Mon Sep 17 00:00:00 2001 From: ULIVZ <472590061@qq.com> Date: Tue, 17 Apr 2018 23:11:32 -0500 Subject: [PATCH] feat: Multiple Language Support + Complete Chinese Translation (#48) --- docs/.vuepress/config.js | 74 +++++-- docs/guide/README.md | 1 - docs/zh/README.md | 34 ++++ docs/zh/config/README.md | 201 +++++++++++++++++++ docs/zh/default-theme-config/README.md | 258 +++++++++++++++++++++++++ docs/zh/guide/README.md | 49 +++++ docs/zh/guide/assets.md | 50 +++++ docs/zh/guide/basic-config.md | 40 ++++ docs/zh/guide/custom-themes.md | 82 ++++++++ docs/zh/guide/deploy.md | 45 +++++ docs/zh/guide/getting-started.md | 66 +++++++ docs/zh/guide/markdown.md | 185 ++++++++++++++++++ docs/zh/guide/using-vue.md | 143 ++++++++++++++ lib/app/dataMixin.js | 31 +++ lib/app/index.ssr.html | 1 + lib/app/util.js | 7 +- lib/build.js | 3 +- lib/default-theme/Home.vue | 4 +- lib/default-theme/Layout.vue | 26 ++- lib/default-theme/NavLinks.vue | 37 +++- lib/default-theme/Navbar.vue | 4 +- lib/prepare.js | 10 +- 22 files changed, 1304 insertions(+), 47 deletions(-) create mode 100644 docs/zh/README.md create mode 100644 docs/zh/config/README.md create mode 100644 docs/zh/default-theme-config/README.md create mode 100644 docs/zh/guide/README.md create mode 100644 docs/zh/guide/assets.md create mode 100644 docs/zh/guide/basic-config.md create mode 100644 docs/zh/guide/custom-themes.md create mode 100644 docs/zh/guide/deploy.md create mode 100644 docs/zh/guide/getting-started.md create mode 100644 docs/zh/guide/markdown.md create mode 100644 docs/zh/guide/using-vue.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 9cece56a58..8bc0b9346a 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -1,8 +1,18 @@ const base = process.env.GH ? '/vuepress/' : '/' module.exports = { - title: 'VuePress', - description: 'Vue-powered Static Site Generator', + langs: [ + { lang: 'en', label: 'English', path: '/', selectText: 'Languages' }, + { lang: 'zh-CN', label: '简体中文', path: '/zh/', selectText: '选择语言' } + ], + title: { + '/': 'VuePress', + '/zh/': 'VuePress' + }, + description: { + '/': 'Vue-powered Static Site Generator', + '/zh/': 'Vue 驱动的静态网站生成器' + }, dest: 'vuepress', base, head: [ @@ -13,20 +23,36 @@ module.exports = { repo: 'vuejs/vuepress', editLinks: true, docsDir: 'docs', - nav: [ - { - text: 'Guide', - link: '/guide/', - }, - { - text: 'Config Reference', - link: '/config/' - }, - { - text: 'Default Theme Config', - link: '/default-theme-config/' - } - ], + nav: { + '/': [ + { + text: 'Guide', + link: '/guide/', + }, + { + text: 'Config Reference', + link: '/config/' + }, + { + text: 'Default Theme Config', + link: '/default-theme-config/' + } + ], + '/zh/': [ + { + text: '指南', + link: '/zh/guide/', + }, + { + text: '配置', + link: '/zh/config/' + }, + { + text: '默认主题', + link: '/zh/default-theme-config/' + } + ] + }, sidebar: { '/guide/': [ { @@ -43,6 +69,22 @@ module.exports = { 'deploy' ] } + ], + '/zh/guide/': [ + { + title: '指南', + collapsable: false, + children: [ + '', + 'getting-started', + 'basic-config', + 'assets', + 'markdown', + 'using-vue', + 'custom-themes', + 'deploy' + ] + } ] } } diff --git a/docs/guide/README.md b/docs/guide/README.md index 0761baa54a..8efd25508e 100644 --- a/docs/guide/README.md +++ b/docs/guide/README.md @@ -30,7 +30,6 @@ Each markdown file is compiled into HTML with [markdown-it](https://github.com/m VuePress is still a work in progress. There are a few things that it currently does not support but are planned: -- Multi-Language Support - Algolia DocSearch Integration - Blogging support diff --git a/docs/zh/README.md b/docs/zh/README.md new file mode 100644 index 0000000000..f5169ad931 --- /dev/null +++ b/docs/zh/README.md @@ -0,0 +1,34 @@ +--- +home: true +heroImage: /hero.png +actionText: 快速上手 → +actionLink: /zh/guide/ +features: +- title: 简洁至上 + details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。 +- title: Vue驱动 + details: 享受 Vue + webpack 的开发体验,可以在 Markdown 中使用 Vue 组件,又可以使用 Vue 来开发自定义主题。 +- title: 高性能 + details: VuePress 会为每个页面预渲染生成静态的 HTML,同时,每个页面被加载的时候,将作为 SPA 运行。 +footer: MIT Licensed | Copyright © 2018-present Evan You +--- + +### 像数 1, 2, 3 一样容易 + +``` bash +# 安装 +yarn global add vuepress # 或者:npm install -g vuepress + +# 新建一个 markdown 文件 +echo '# Hello VuePress!' > README.md + +# 开始写作 +vuepress dev . + +# 构建静态文件 +vuepress build . +``` + +::: warning NODE VERSION +请确保你 Node.js 的版本大于 8。 +::: diff --git a/docs/zh/config/README.md b/docs/zh/config/README.md new file mode 100644 index 0000000000..0340b4ccbb --- /dev/null +++ b/docs/zh/config/README.md @@ -0,0 +1,201 @@ +--- +sidebar: auto +--- + +# 配置 + +## 基本配置 + +### base + +- 类型: `string` +- 默认值: `/` + +部署站点的基础路径,如果你想让你的网站部署到一个子路径下,你将需要设置它。如 Github pages,如果你想将你的网站部署到 `https://foo.github.io/bar/`,那么 `base` 应该被设置成 `"/bar/"`,它的值应当总是以斜杠开始,并以斜杠结束。 + +`base` 将会自动地作为前缀插入到所有以 `/` 开始的其他选项的链接中,所以你只需要指定一次。 + +**Also see:** + +- [Base URL](../guide/assets.md#base-url) +- [部署指南 > Github Pages](../guide/deploy.md#github-pages) + +### title + +- 类型: `string` +- 默认值: `undefined` + +网站的标题,它将会被用作所有页面标题的前缀,同时,默认主题下,它将显示在导航栏(navbar)上。 + +### description + +- 类型: `string` +- 默认值: `undefined` + +网站的描述,它将会以 `` 标签渲染到当前页面的 HTML 中。 + +### head + +- 类型: `Array` +- 默认值: `[]` + +额外的需要被注入到当前页面的 HTML `` 中的标签,每个标签都可以以 `[tagName, { attrName: attrValue }, innerHTML?]` 的格式指定,举个例子,增加一个自定义的 favicon: + +``` js +module.exports = { + head: [ + ['link', { rel: 'icon', href: `/logo.png` }] + ] +} +``` + +### host + +- Type: `string` +- Default: `'0.0.0.0'` + +指定用于 dev server 的主机名。 + +### port + +- 类型: `number` +- 默认值: `8080` + +指定 dev server 的端口。 + +### dest + +- 类型: `string` +- 默认值: `.vuepress/dist` + +指定 `vuepress build` 的输出目录。 + +### ga + +- 类型: `string` +- 默认值: `undefined` + +提供一个 Google Analytics ID 来使 GA 生效。 + +### serviceWorker + +- 类型: `boolean` +- 默认值: `false` + +如果设置成 `true`,VuePress 将会自动生成并且注册一个 service worker,它缓存了那些已访问过的页面的内容,用于离线访问(仅在生产环境生效)。 + +如果你正在开发一个自定义主题,`Layout.vue` 组件将会自动触发下述的事件: + +- `sw-ready` +- `sw-cached` +- `sw-updated` +- `sw-offline` +- `sw-error` + +::: tip PWA NOTES +`serviceWorker` 仅仅用来控制 service worker,为了让你的网站完全地兼容 PWA,你需要在 `.vuepress/public` 提供 Manifest 和 icons,更多细节,请参见 [MDN docs about the Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest). +当然,仅仅只在你的网站部署后能用 SSL 的时候开启它,因为 service worker 只能在 HTTPs 的链接下注册。 +::: + +## 主题 + +### theme + +- 类型: `string` +- 默认值: `undefined` + +当你使用自定义主题的时候,需要指定它。当值为 `"foo"` 时,VuePress 将会尝试去加载位于 `node_modules/vuepress-theme-awesome/Layout.vue` 的主题组件。 + +### themeConfig + +- 类型: `Object` +- 默认值: `{}` + +为当前的主题提供一些配置,这些选项依赖于你正在使用的主题。 + +**也可以参考:** + +- [默认主题](../default-theme-config/)。 + +## Markdown + +### markdown.anchor + +- 类型: `Object` +- 默认值: `{ permalink: true, permalinkBefore: true, permalinkSymbol: '#' }` + +[markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor) 的选项。 + +### markdown.toc + +- 类型: `Object` +- 默认值: `{ includeLevel: [2, 3] }` + +[markdown-it-table-of-contents](https://github.com/Oktavilla/markdown-it-table-of-contents) 的选项。 + +### markdown.config + +- 类型: `Function` +- 默认值: `undefined` + +一个用来对当前的 [markdown-it](https://github.com/markdown-it/markdown-it) 实例应用额外的插件的函数,举例如下: + +``` js +module.exports = { + markdown: { + config: md => { + md.use(require('markdown-it-xxx')) + } + } +} +``` + +## 构建流程 + +### postcss + +- 类型: `Object` +- 默认值: `{ plugins: [require('autoprefixer')] }` + +[postcss-loader](https://github.com/postcss/postcss-loader) 的选项,请注意,指定这个值,将会覆盖内置的 autoprefixer,所以你需要自己将它加进去。 + +### configureWebpack + +- 类型: `Object | Function` +- 默认值: `undefined` + +用于修改内部的 Webpack 配置。如果给定一个对象,那么它将会被 [webpack-merge](https://github.com/survivejs/webpack-merge) 合并到最终的配置中,如果给定一个函数,它将会接受 `config` 作为第一个参数,以及 `isServer` 作为第二个参数,你可以直接更改 `config`,也可以返回一个待合并的对象。 + +``` js +module.exports = { + configureWebpack: (config, isServer) => { + if (!isServer) { + // 修改客户端的 webpack 配置 + } + } +} +``` + +### chainWebpack + +- 类型: `Function` +- 默认值: `undefined` + +通过 [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain) 来修改内部的 Webpack 配置。 + +``` js +module.exports = { + chainWebpack: (config, isServer) => { + // config 是 ChainableConfig 的一个实例 + } +} +``` + +## 浏览器兼容性 + +### evergreen + +- 类型: `boolean` +- 默认值: `false` + +如果你的对象只有那些 “常青树” 浏览器,你可以将其设置成 `true`,这将会禁止 ESNext 到 ES5 的转译以及对 IE 的 polyfills,同时会带来更快的构建速度和更小的文件体积。 diff --git a/docs/zh/default-theme-config/README.md b/docs/zh/default-theme-config/README.md new file mode 100644 index 0000000000..22279b06ce --- /dev/null +++ b/docs/zh/default-theme-config/README.md @@ -0,0 +1,258 @@ +--- +sidebar: auto +--- + +# 默认主题 + +::: tip +所有列在这一页的选项仅对默认的主题生效。如果你在使用一个自定义主题,选项可能会有不同。 +::: + +## 首页 + +默认的主题提供了一个首页(Homepage)的布局 (用于 [这个网站的主页](/zh/))。想要使用它,需要在你的根级 `README.md` 的 [YAML front matter](../guide/markdown.md#yaml-front-matter) 指定 `home: true`。以下是这个网站实际使用的数据: + +``` yaml +--- +home: true +heroImage: /hero.png +actionText: 快速上手 → +actionLink: /zh/guide/ +features: +- title: 简洁至上 + details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。 +- title: Vue驱动 + details: 享受 Vue + webpack 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题。 +- title: 高性能 + details: VuePress 为每个页面预渲染生成静态的 HTML,同时在页面被加载的时候,将作为 SPA 运行。 +footer: MIT Licensed | Copyright © 2018-present Evan You +--- +``` + +任何 `YAML front matter` 之后额外的内容将会以普通的 markdown 被渲染,并插入到 `features` 的后面。 + +## 导航栏 + +你可以通过 `themeConfig.nav` 增加一些导航链接: + +``` js +// .vuepress/config.js +module.exports = { + themeConfig: { + nav: [ + { text: 'Home', link: '/' }, + { text: 'Guide', link: '/guide/' }, + { text: 'External', link: 'https://google.com' }, + ] + } +} +``` + +当你提供了一个 `items` 数组而不是一个单一的 `link` 时,它将会显示以 `下拉列表` 的方式显示: + +```js +// .vuepress/config.js +module.exports = { + themeConfig: { + nav: [ + { text: 'Home', link: '/' }, + { text: 'Guide', link: '/guide/' }, + { text: 'External', link: 'https://google.com' }, + ] + } +} +``` + +此外,你还可以通过嵌套的 `items` 来在 `下拉列表` 中设置分组: + +```js +module.exports = { + themeConfig: { + nav: [ + { + text: 'Languages', + items: [ + { text: 'Group1', items: [/* */] }, + { text: 'Group2', items: [/* */] } + ] + } + ] + } +} +``` + +## 侧边栏 + +想要使 侧边栏(Sidebar)生效,需要配置 `themeConfig.sidebar`,基本的配置,需要一个包含了多个链接的数组: + +``` js +// .vuepress/config.js +module.exports = { + themeConfig: { + sidebar: [ + '/', + '/page-a', + ['/page-b', 'Explicit link text'] + ] + } +} +``` + +你可以省略 `.md` 拓展名,同时以 `/` 结尾的路径将会被视为 `*/README.md`,这个链接的文字将会被自动获取到(无论你是声明为页面的第一个 header,还是明确地在 `YAML front matter` 中指定页面的标题)。如果你想要显示地指定链接的文字,使用一个格式为 `[link, text]` 的数组。 + +### 嵌套的标题链接 + +默认情况下,侧边栏会自动地显示由当前页面标的题(headers)组成的的链接,并按照页面本身的结构进行嵌套,你可以通过 `themeConfig.sidebarDepth` 来修改它的行为。默认的深度是 `1`,它将提取到 `h2` 的标题,设置成 `0` 将会禁用标题(headers)链接,同时,最大的深度为 `2`,它将同时提取 `h2` 和 `h3` 标题。 + +也可以使用 `YAML front matter` 来为某个页面重写此值: + +``` md +--- +sidebarDepth: 2 +--- +``` + +### 侧边栏分组 + +你可以通过使用**对象**来将侧边栏划分成多个组: + +``` js +// .vuepress/config.js +module.exports = { + themeConfig: { + sidebar: [ + { + title: 'Group 1', + collapsable: false, + children: [ + '/' + ] + }, + { + title: 'Group 2', + children: [ /* ... */ ] + } + ] + } +} +``` + +侧边栏的每个子组默认是可折叠的,你可以设置 `collapsable: false` 来让一个组永远都是展开状态。 + +### 多个侧边栏 + +如果你想为不同的页面组来显示不同的侧边栏,首先,将你的页面文件组织成下述的目录结构: + +``` +. +├─ README.md +├─ foo +│  ├─ README.md +│ ├─ one.md +│ └─ two.md +└─ bar + ├─ README.md + ├─ three.md + └─ four.md +``` + +接着,遵循以下的侧边栏配置: + +``` js +// .vuepress/config.js +module.exports = { + themeConfig: { + sidebar: { + // sidebar for pages under /foo/ + '/foo/': [ + '', + 'one', + 'two' + ], + // sidebar for pages under /bar/ + '/bar/': [ + '', + 'three', + 'four' + ] + } + } +} +``` + +### 自动生成侧栏 + +如果你希望自动生成一个仅仅包含了当前页面标题(headers)链接的侧边栏,你可以通过 `YAML front matter` 来实现: + +``` yaml +--- +sidebar: auto +--- +``` + +### 禁用侧边栏 + +你可以通过 `YAML front matter` 来禁用指定页面的侧边栏: + +``` yaml +--- +sidebar: false +--- +``` + +## 上 / 下一篇链接 + +上一篇和下一篇文章的链接将会自动地根据当前页面的侧边栏的顺序来获取。你也可以使用 `YAML front matter` 来明确地重写或者禁用它: + +``` yaml +--- +prev: ./some-other-page +next: false +--- +``` + +## Github 和编辑链接 + +当你提供了 `themeConfig.repo` 选项,将会自动在每个页面的导航栏生成生成一个 GitHub 链接,以及在页面的底部生成一个 `"Edit this page"` 链接。 + +``` js +// .vuepress/config.js +module.exports = { + themeConfig: { + // 假定是 GitHub. 同时也可以是一个完整的 GitLab URL + repo: 'vuejs/vuepress', + // 当你的文档不是仓库的根目录时需要设置 + docsDir: 'docs', + // 可选的, 默认是 master + docsBranch: 'master', + // 默认是 true, 设置为 false 来禁用 + editLinks: true + } +} +``` + +## 简单的 CSS 覆盖 + +如果你只是希望应用一些简单的 overrides 到默认主题的样式上,你可以创建一个 `.vuepress/override.styl` 文件,这是一个 [Stylus](http://stylus-lang.com/) 文件,但是你仍然可以使用普通的 CSS 语法。 + +这里有一些你可以调整的颜色变量: + +``` stylus +// showing default values +$accentColor = #3eaf7c +$textColor = #2c3e50 +$borderColor = #eaecef +$codeBgColor = #282c34 +``` + +## 特定页面的自定义布局 + +默认情况下,每个 `*.md` 文件将会被渲染在一个 `
` 容器中,同时还有侧边栏、自动生成的编辑链接,以及上 / 下一篇文章的链接。如果你想要使用一个完全自定义的组件来代替当前的页面(而只保留导航栏),你可以再次使用 `YAML front matter` 来指定这个组件。 + +``` yaml +--- +layout: SpecialLayout +--- +``` + +这将会为当前的页面渲染 `.vuepress/components/SpecialLayout/vue` 布局。 diff --git a/docs/zh/guide/README.md b/docs/zh/guide/README.md new file mode 100644 index 0000000000..404f4ca914 --- /dev/null +++ b/docs/zh/guide/README.md @@ -0,0 +1,49 @@ +# 介绍 + +VuePress 由两部分组成:一个是由 Vue 驱动的极简主题系统带来的静态网站生成器,一个是为书写技术文档而优化的默认主题,它的诞生初衷是为了助力 Vue 及其子项目书写文档的需求。 + +每一个由 VuePress 生成的页面都有自己预渲染好的 HTML,也因此带来了非常好的加载性能和搜索引擎优化(SEO)。同时,一旦页面被加载,Vue 将接管这些静态内容,并将其转换成一个完整的单页应用(SPA),其他的页面都将在用户浏览到的时候按需加载。 + +## 它是如何工作的? + +事实上,一个 VuePress 网站是一个由 [Vue](http://vuejs.org/)、[Vue Router](https://github.com/vuejs/vue-router) 和 [Webpack](http://webpack.js.org/) 驱动的单页应用。如果你以前使用过 Vue 的话,当你在开发一个自定义主题的时候,你将会回到曾经那非常熟悉的开发体验,你甚至可以使用 Vue DevTools 去调试你的自定义主题。 + +在构建过程中,我们创建了一个服务端渲染(SSR)版本的应用,同时在访问每一个路由的时候会渲染对应的HTML,这种做法的灵感来源于 [Nuxt](https://nuxtjs.org/) 的 `nuxt generate` 命令,以及其他的一些项目,如 [Gatsby](https://www.gatsbyjs.org/)。 + +## 特性 + +- [内置的 Markdown 拓展](./markdown.md),为技术文档而生 +- [在 Markdown 文件使用 Vue 组件的能力](./using-vue.md) +- [Vue 驱动的自定义主题系统](./custom-themes.md) +- 支持 PWA +- 集成了 Google Analytics +- 一个默认的主题包含: + - 响应式布局 + - 可选的主页 + - 简洁的开箱即用的标题搜索 + - 可以自定义的导航栏(navbar)和侧边栏(sidebar) + - 自动生成的 GitHub 链接和页面的编辑链接 + +## Todo + +VuePress 仍然处于开发中,这里有一些目前还不支持、但已经在计划中的特性: + +- Algolia DocSearch 的集成 +- 博客系统 + +欢迎你的 Contribution! + +## 为什么不是...? + +### Nuxt + +VuePress 能做的事情,Nuxt 同样能胜任,但 Nuxt 是为构建应用程序而生的,而 VuePress 则专注在以内容为中心的静态网站上,同时提供了一些为技术文档定制的开箱即用的特性。 + +### Docsify / Docute + +这两个项目同样都是 Vue 驱动的,然而它们都是完全的运行时驱动,因此对 SEO 不够友好。如果你并不关注 SEO,同时也不想因为安装依赖而弄糊涂,它们仍然是非常好的选择! + +### Hexo + +Hexo 一直驱动着 Vue 的文档 —— 事实上,在决定开始从 Hexo 迁移到 VuePress 之前,我们还有很长的路要走。Hexo 最大的问题在于他的主题系统太过于静态以及过度地依赖纯字符串,而我们十分希望能够好好地利用 Vue 来处理我们的布局和交互,同时,Hexo 的 Markdown 渲染的配置也不是最灵活的。 + diff --git a/docs/zh/guide/assets.md b/docs/zh/guide/assets.md new file mode 100644 index 0000000000..d5171cd6a3 --- /dev/null +++ b/docs/zh/guide/assets.md @@ -0,0 +1,50 @@ +# 静态资源 + +## 相对路径 + +所有的 Markdown 文件都会被 webpack 编译成 Vue 组件,因此你可以,并且**应该更倾向于**使用相对路径(Relative URLs)来引用所有的静态资源: + +``` md +![An image](./image.png) +``` + +同样地,这在 `*.vue` 文件的模板中一样可以工作,图片将会被 `url-loader` 和 `file-loader` 处理,在运行生成静态文件的构建任务时,文件会被复制到正确的位置。 + +除此之外,你也使用 `~` 前缀来明确地指出这是一个 webpack 的模块请求,这将允许你通过 webpack 别名来引用文件或者 npm 的依赖: + +``` md +![Image from alias](~@alias/image.png) +![Image from dependency](~some-dependency/image.png) +``` + +Webpack 的别名可以通过 `.vuepress/config.js` 中 [configureWebpack](/zh/config/#configurewebpack) 来配置,如: + +``` js +module.exports = { + configureWebpack: { + resolve: { + alias: { + '@alias': 'path/to/some/dir' + } + } + } +} +``` + +## 公共文件 + +有时,你可能需要提供一个静态资源,但是它们并不直接被你的任何一个 markdown 文件或者主题组件引用 —— 举例来说,favicons 和 PWA 的图标,在这种情形下,你可以将它们放在 `.vuepress/public` 中, 它们最终会被复制到生成的静态文件夹中。 + +## 基础路径 + +如果你的网站会被部署到一个**非根路径**,你将需要在 `.vuepress/config.js` 中设置 `base`,举例来说,如果你打算将你的网站部署到 `https://foo.github.io/bar/`,那么 `base` 的值就应该被设置为 `"/bar/"` (应当总是以斜杠开始,并以斜杠结束)。 + +有了基础路径(Base URL),如果你希望引用一张放在 `.vuepress/public` 中的图片,你需要使用这样路径:`/bar/image.png`,然而,一旦某一天你决定去修改 `base`,这样的路径引用将会显得异常脆弱。为了解决这个问题,VuePress 提供了内置的一个 helper `$withBase`(它被注入到了 Vue 的原型上),可以帮助你生成正确的路径: + +``` vue +foo +``` + +值得一提的是,你不仅可以在你的 Vue 组件中使用上述的语法,在 Markdown 文件中亦是如此。 + +最后补充一句,一个 `base` 路径一旦被设置,它将会自动地作为前缀插入到 `.vuepress/config.js` 中所有以 `/` 开始的资源路径中。 diff --git a/docs/zh/guide/basic-config.md b/docs/zh/guide/basic-config.md new file mode 100644 index 0000000000..c9247f56a2 --- /dev/null +++ b/docs/zh/guide/basic-config.md @@ -0,0 +1,40 @@ +# 基本配置 + +## 配置文件 + +如果没有任何配置,这个网站将会是非常局限的,用户也无法在你的网站上自由导航。为了更好地自定义你的网站,让我们首先在你的文档目录下创建一个 `.vuepress` 目录,所有 VuePress 相关的文件都将会被放在这里。 + +一个 VuePress 网站必要的配置文件是 `.vuepress/config.js`,它应该导出一个 JavaScript 对象: + +``` js +module.exports = { + title: 'Hello VuePress', + description: 'Just playing around' +} +``` + +对于上述的配置,如果你运行起 dev server,你应该能看到一个页面,它包含一个页头,里面包含一个标题和一个搜索框。VuePress 内置了基于 headers 的搜索 —— 它会自动为所有页面的标题、`h2` 和 `h3` 构建起一个简单的搜索索引。 + +参见 [配置](../config/) 来查看所有可配置的选项。 + + +## 主题配置 + +一个 VuePress 主题应该负责整个网站的布局和交互细节。在 VuePress 中,目前自带了一个默认的主题(正是你现在所看到的),它是为技术文档而设计的。同时,默认主题提供了一些选项,让你可以去自定义导航栏(navbar)、 侧边栏(sidebar)和 首页(homepage) 等,详情请参见 [默认主题](../default-theme-config/) 。 + +如果你想开发一个自定义主题,可以参考 [自定义主题](./custom-themes.md)。 + + +## 应用级别的优化 + +由于 VuePress 是一个标准的 Vue 应用,你可以通过创建一个 `.vuepress/enhanceApp.js` 文件来做一些应用级别的优化,当该文件存在的时候,会被导入到应用内部。`enhanceApp.js` 应该 `export default` 一个钩子函数,并接受一个包含了一些应用级别属性的对象作为参数。你可以使用这个钩子来安装一些附加的 Vue 插件、注册全局组件,或者增加额外的路由钩子等: + +```js +export default ({ + Vue, // VuePress 正在使用的 Vue 构造函数 + options, // 附加到根实例的一些选项 + router // 当前应用的路由实例 +}) => { + // ...做一些其他的应用级别的优化 +} +``` diff --git a/docs/zh/guide/custom-themes.md b/docs/zh/guide/custom-themes.md new file mode 100644 index 0000000000..4939e78bbe --- /dev/null +++ b/docs/zh/guide/custom-themes.md @@ -0,0 +1,82 @@ +# 自定义主题 + +::: tip +主题组件受到同样的 [浏览器的 API 访问限制](./using-vue.md#browser-api-access-restrictions)。 +::: + +VuePress 使用单文件组件来构建自定义主题。想要开发一个自定义主题,首先在你的文档根目录新建一个 `.vuepress/theme` 文件夹,然后再创建一个 `Layout.vue` 文件: + +``` +. +└─ .vuepress +   └─ theme +    └─ Layout.vue +``` + +从这里开始,就和开发一个平时的 Vue 应用一样了,这完全取决于你如何组织你的主题。 + +## 网站和页面的元数据 + +`Layout` 组件将会对每一个文档目录下的 `.md` 执行一次,同时,整个网站以及特定页面的元数据将分别暴露为 `this.$site` 和 `this.$page` 属性,它们将会被注入到每一个当前应用的组件中。 + +这是你现在看到的这个网站的 `$site` 的值: + +``` json +{ + "title": "VuePress", + "description": "Vue 驱动的静态网站生成器", + "base": "/", + "pages": [ + { + "path": "/", + "title": "VuePress", + "frontmatter": {} + }, + ... + ] +} +``` + +`title`, `description` 和 `base` 会从 `.vuepress/config.js` 中对应的的字段复制过来,而 `pages` 是一个包含了每个页面元数据对象的数据,包括它的路径、页面标题(明确地通过 [YAML front matter](./markdown.md#yaml-front-matter) 指定,或者通过该页面的第一个标题取到),以及所有源文件中的 `YAML front matter` 的数据。 + +下面的这个对象是你正在看的这个页面的 `$page` 的值: + +``` json +{ + "path": "/custom-themes.html", + "title": "Custom Themes", + "headers": [/* ... */], + "frontmatter": {} +} +``` + +如果用户在 `.vuepress/config.js` 配置了 `themeConfig`,你将可以通过 `$site.themeConfig` 访问到它。如此一来,你可以通过它来对用户开放一些自定义主题的配置 —— 比如指定目录或者页面的顺序,你也可以结合 `$site.pages` 来动态地构建导航链接。 + +最后,别忘了,作为 Vue Router API 的一部分,`this.$route` 和 `this.$router` 同样可以使用。 + +## 获取渲染内容 + +当前的 `.md` 文件渲染的内容,可以作为一个独特的全局组件 `` 来使用,你可能想要它显示在页面中的某个地方。一个最简单的主题,可以是一个唯一的 `Layout.vue` 组件,并包含以下内容: + +``` html + +``` + +## 使用来自 npm 的主题 + +主题可以以 Vue 单文件组件的格式,并以 `vuepress-theme-xxx` 的名称发布到 npm 上。 + +如果想使用一个来自 npm 的主题,你需要在 `.vuepress/config.js` 补充 `theme` 选项: + +``` js +module.exports = { + theme: 'awesome' +} +``` + +VuePress 将会尝试去加载并使用位于 `node_modules/vuepress-theme-awesome/Layout.vue` 的主题组件。 + diff --git a/docs/zh/guide/deploy.md b/docs/zh/guide/deploy.md new file mode 100644 index 0000000000..bca25abb98 --- /dev/null +++ b/docs/zh/guide/deploy.md @@ -0,0 +1,45 @@ +# 部署 + +下述的指南,将假定你将文档放置在项目的 `docs` 目录中,并使用默认的构建输出位置。 + +## GitHub Pages + +1. 将 `.vuepress/config.js` 的 `base` 设置成你仓库的名字,举个例子,如果你的仓库是 `https://github.com/foo/bar`, 部署的页面将会通过 `https://foo.github.io/bar` 来访问,此时,你应该将 `base` 设置为 `"/bar/"`。 +2. 在你的项目中运行: + +``` bash +# 构建静态文件 +vuepress build docs + +# 切换到你的输出目录 +cd docs/.vuepress/dist + +git init +git add -A +git commit -m 'deploy' + +# push 到你仓库的 gh-pages 分支 +# 将 / 替换成你的信息 +git push -f git@github.com:/.git master:gh-pages +``` + +你可以在你的持续集成的设置中,设置在每次 push 代码时自动运行上述脚本。 + +## Netlify + +1. 确保你已经有了构建你的文档的的 npm scripts: + +``` json +{ + "scripts": { + "build-docs": "vuepress build docs" + } +} +``` + +2. 在 Netlify 中, 创建一个新的 Github 项目,并做一下设置: + + - **Build Command:** `npm run build-docs` 或者 `yarn build-docs` + - **Publish directory:** `docs/.vuepress/dist` + +3. 点击 deploy 按钮! diff --git a/docs/zh/guide/getting-started.md b/docs/zh/guide/getting-started.md new file mode 100644 index 0000000000..3242553077 --- /dev/null +++ b/docs/zh/guide/getting-started.md @@ -0,0 +1,66 @@ +# 快速上手 + +## 全局安装 + +如果你只是想玩一玩 VuePress,你可以全局安装它: + +``` bash +# 安装 +yarn global add vuepress # 或者:npm install -g vuepress + +# 新建一个 markdown 文件 +echo "# Hello VuePress!" > README.md + +# 开始写作 +vuepress dev . + +# 构建静态文件 +vuepress build . +``` + +## 现有项目 + +如果你想在一个现有项目中使用 VuePress,同时想要在该项目中保存文档,此时你应该将 VuePress 作为本地依赖。下述的安装流程,你同样可以使用持续集成工具,或者一些开源服务,如 Netlify,来帮助你在每次更新代码时自动部署。 + +``` bash +# 将 VuePress 作为一个本地依赖安装 +yarn add -D vuepress # 或者:npm install -D vuepress + +# 新建一个 docs 文件夹 +mkdir docs + +# 新建一个 markdown 文件 +echo "# Hello VuePress!" > docs/README.md + +# 开始写作 +npx vuepress dev docs +``` + +::: warning +当你想要将 VuePress 安装到一个现存的项目中,并且这个项目已经有了 webpack 3.x 作为依赖时,推荐使用 [Yarn](https://yarnpkg.com/en/) 而不是 npm,因为在这种情形下,npm 会生成错误的依赖树。 +::: + +接着,你可以在 `package.json` 加一些脚本: + +``` json +{ + "scripts": { + "docs:dev": "vuepress dev docs", + "docs:build": "vuepress build docs" + } +} +``` + +于是,你就可以这样开始你的写作了: + +``` bash +yarn docs:dev # 或者:npm run docs:dev +``` + +要生成静态资源时,运行: + +``` bash +yarn docs:build # 或者:npm run docs:build +``` + +默认情况下,文件将会被生成在 `.vuepress/dist`,当然,你也可以通过 `.vuepress/config.js` 中的 `dest` 字段来修改,生成的文件可以部署到任意的静态文件服务器上,参考 [部署](./deploy.md) 来了解更多。 diff --git a/docs/zh/guide/markdown.md b/docs/zh/guide/markdown.md new file mode 100644 index 0000000000..c1a052d7fc --- /dev/null +++ b/docs/zh/guide/markdown.md @@ -0,0 +1,185 @@ +--- +meta: +- name: keywords + content: static docs generator vue +--- + +# Markdown 拓展 + +## Header Anchors + +所有的标题将会自动地应用 anchor 链接,anchor 的渲染可以通过 [`markdown.anchor`](../config/#markdownanchor) 来配置。 + +## 链接 + +- 内部的、并以 `.md` or `.html` 结尾的链接,将会被转换成 `` 用于 SPA 导航。 + + - [首页](/zh/) + - [Markdown 的配置](../config/#markdown) + +- 外部的链接将会被自动地设置为 `target="_blank"`: + + - [vuejs.org](https://vuejs.org) + - [VuePress on GitHub](https://github.com/vuejs/vuepress) + +## YAML Front Matter + +VuePress 提供了对 [YAML front matter](https://jekyllrb.com/docs/frontmatter/) 开箱即用的支持: + +``` yaml +--- +title: Blogging Like a Hacker +lang: en-US +--- +``` + +这些数据可以在当前页的正文中使用,在任意的自定义或主题组件中,它可以通过 `$page` 来访问。 + +`title` 和 `lang` 的 meta 将会被自动地注入到当前的页面中,当然你也可以指定一些额外需要注入的 meta: + +``` yaml +--- +meta: + - name: description + content: hello + - name: keywords + content: super duper SEO +--- +``` + +## GitHub 风格的表格 + +**Input** + +``` +| Tables | Are | Cool | +| ------------- |:-------------:| -----:| +| col 3 is | right-aligned | $1600 | +| col 2 is | centered | $12 | +| zebra stripes | are neat | $1 | +``` + +**Output** + +| Tables | Are | Cool | +| ------------- |:-------------:| -----:| +| col 3 is | right-aligned | $1600 | +| col 2 is | centered | $12 | +| zebra stripes | are neat | $1 | + +## Emoji + +**Input** + +``` +:tada: :100: +``` + +**Output** + +:tada: :100: + +## 目录 + +**Input** + +``` +[[toc]] +``` + +**Output** + +[[toc]] + +目录(Table of Contents)的渲染可以通过 [`markdown.toc`](../config/#markdowntoc) 选项来配置。 + +## 自定义容器 + +**Input** + +``` +::: tip +This is a tip +::: + +::: warning +This is a warning +::: + +::: danger +This is a dangerous warning +::: +``` + +**Output** + +::: tip +This is a tip +::: + +::: warning +This is a warning +::: + +::: danger +This is a dangerous thing +::: + +你也可以自定义块中的标题: + +``` +::: danger STOP +Danger zone, do not proceed +::: +``` + +::: danger STOP +Danger zone, do not proceed +::: + +## 代码块中的行高亮 + +**Input** + +```` +``` js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` +```` + +**Output** + +``` js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` + +## 进阶配置 + +VuePress 使用 [markdown-it](https://github.com/markdown-it/markdown-it) 来渲染 Markdown,上述大多数的拓展也都是通过自定义的插件实现的。想要进一步的话,你可以通过 `.vuepress/config.js` 的 `markdown` 选项,来对当前的 `markdown-it` 实例做一些自定义的配置: + +``` js +module.exports = { + markdown: { + // markdown-it-anchor 的选项 + anchor: { permalink: false }, + // markdown-it-toc 的选项 + toc: { includeLevel: [1, 2] }, + config: md => { + // 使用更过的 markdown-it 插件! + md.use(require('markdown-it-xxx')) + } + } +} +``` diff --git a/docs/zh/guide/using-vue.md b/docs/zh/guide/using-vue.md new file mode 100644 index 0000000000..d2a8facdca --- /dev/null +++ b/docs/zh/guide/using-vue.md @@ -0,0 +1,143 @@ +# 在 Markdown 中 使用 Vue + +## 浏览器的 API 访问限制 + +当你在开发一个 VuePress 应用时,由于所有的页面都是通过 Node.js 服务端渲染的,因此任意的 Vue 使用都应当遵循 [编写通用代码](https://ssr.vuejs.org/zh/universal.html) 的要求。简而言之,请确保只在 `beforeMounted` 或者 `mounted` 访问浏览器 / DOM 的 API。 + +如果你正在使用,或者测试一个对于 SSR 不怎么友好的组件(比如包含了自定义指令),你可以将他们包裹在内置的 `` 指令中: + +``` md + + + +``` + +请注意,这并不能解决在**导入**时,这些组件或者库不能访问浏览器 API 的问题 —— 为了使用上述假定的仅能运行在浏览器环境下的代码,你需要在合适的生命周期钩子中**动态导入**它们: + +``` vue + +``` + +## 模板语法 + +### 插值 + +每一个 Markdown 文件将首先被编译成 HTML,接着作为一个 Vue 组件传入 `vue-loader`,这意味着你可以在文本中使用 Vue 风格的插值: + +**Input** + +``` md +{{ 1 + 1 }} +``` + +**Output** + +
{{ 1 + 1 }}
+ +### 指令 + +同样地,也可以使用指令: + +**Input** + +``` md +{{ i }} +``` + +**Output** + +
{{ i }} 
+ +### 访问网站以及页面的数据 + +编译后的组件没有任何的私有数据,也可以访问 [网站的元数据](./custom-themes.md#site-and-page-metadata),举例来说: + +**Input** + +``` md +{{ $page }} +``` + +**Output** + +``` json +{ + "path": "/using-vue.html", + "title": "Using Vue in Markdown", + "frontmatter": {} +} +``` + +## Escaping + +默认情况下,代码块将会默认地包裹在 `v-pre` 中,如果你想要在代码块或者文本中显示原始的大括号,或者一些 Vue 特定的语法,你需要使用自定义容器 `v-pre` 来包裹: + +**Input** + +``` md +::: v-pre +`{{ This will be displayed as-is }}` +::: +``` + +**Output** + +::: v-pre +`{{ This will be displayed as-is }}` +::: + +## 使用组件 + +所有在 `.vuepress/components` 中找到的 `*.vue` 文件将会自动地被注册为全局的异步组件,如: + +``` +. +└─ .vuepress +   └─ components + ├─ demo-1.vue +     └─ OtherComponent.vue +``` + +你可以直接使用这些组件在任意的 Markdown 文件中(组件名是通过文件名取到的): + +``` md + + +``` + + + + + +::: warning IMPORTANT +请确保一个自定义组件的名字包含连接符或者是PascalCase,否则,它将会被视为一个内联元素,并被包裹在一个 `

` 标签中,这将会导致 HTML 渲染紊乱,因为 HTML 标准规定, `

` 标签中不允许放置任何块级元素。 +::: + +## 脚本和样式提升 + +有时,你可以只想在当前页面应用一些 JavaScript 或者 CSS,在这种情况下,你可以直接在 Markdown 文件中使用原生的 ` diff --git a/lib/app/dataMixin.js b/lib/app/dataMixin.js index b00b0c2784..701f354d93 100644 --- a/lib/app/dataMixin.js +++ b/lib/app/dataMixin.js @@ -28,6 +28,37 @@ export default { $site () { return store.siteData }, + $title () { + const title = this.$site.title + return typeof title === 'object' + ? title[this.$basepath] + : title + }, + $description () { + const description = this.$site.description + return typeof description === 'object' + ? description[this.$basepath] + : description + }, + $langConfig () { + const { langs } = this.$site + let targetLang + let defaultLang + (langs || []).forEach((lang, index) => { + if (lang.path === '/') { + defaultLang = langs[index] + } else if (this.$page.path.indexOf(lang.path) === 0) { + targetLang = langs[index] + } + }) + return targetLang || defaultLang + }, + $lang () { + return this.$langConfig && this.$langConfig.lang || 'en' + }, + $basepath () { + return this.$langConfig && this.$langConfig.path || '/' + }, $page () { return findPageForPath( this.$site.pages, diff --git a/lib/app/index.ssr.html b/lib/app/index.ssr.html index 8a5dc96b54..32d310a9b3 100644 --- a/lib/app/index.ssr.html +++ b/lib/app/index.ssr.html @@ -4,6 +4,7 @@ {{ title }} + {{{ userHeadTags }}} {{{ pageMeta }}} {{{ renderResourceHints() }}} diff --git a/lib/app/util.js b/lib/app/util.js index 5c4b27fa0a..0481dfec30 100644 --- a/lib/app/util.js +++ b/lib/app/util.js @@ -15,19 +15,14 @@ export function findPageForPath (pages, path) { } } -export function getTitle (siteData, page) { +export function getTitle (siteTitle, page) { const selfTitle = page.frontmatter.home ? null : ( page.frontmatter.title || // explicit title page.title // inferred title ) - const siteTitle = siteData.title return siteTitle ? selfTitle ? (siteTitle + ' | ' + selfTitle) : siteTitle : selfTitle || 'VuePress' } - -export function getLang (page) { - return page.frontmatter.lang || 'en' -} diff --git a/lib/build.js b/lib/build.js index e410871176..cd9b67ef7b 100644 --- a/lib/build.js +++ b/lib/build.js @@ -134,7 +134,8 @@ module.exports = async function build (sourceDir, cliOptions = {}) { userHeadTags, pageMeta, title: 'VuePress', - lang: 'en' + lang: 'en', + description: '' } let html diff --git a/lib/default-theme/Home.vue b/lib/default-theme/Home.vue index 9e04756d0c..9e1df5485c 100644 --- a/lib/default-theme/Home.vue +++ b/lib/default-theme/Home.vue @@ -2,9 +2,9 @@

hero -

{{ data.heroText || $site.title }}

+

{{ data.heroText || $title }}

- {{ data.tagline || $site.description }} + {{ data.tagline || $description }}

diff --git a/lib/default-theme/Layout.vue b/lib/default-theme/Layout.vue index e1ec1a427a..91ecbfea86 100644 --- a/lib/default-theme/Layout.vue +++ b/lib/default-theme/Layout.vue @@ -75,18 +75,27 @@ export default { created () { if (this.$ssrContext) { - this.$ssrContext.title = getTitle(this.$site, this.$page) - this.$ssrContext.lang = getLang(this.$page) + this.$ssrContext.title = getTitle(this.$title, this.$page) + this.$ssrContext.lang = this.$lang + this.$ssrContext.description = this.$page.description || this.$description } + }, mounted () { // update title / meta tags this.currentMetaTags = [] const updateMeta = () => { - document.title = getTitle(this.$site, this.$page) - document.documentElement.lang = getLang(this.$page) - this.currentMetaTags = updateMetaTags(this.$page, this.currentMetaTags) + document.title = getTitle(this.$title, this.$page) + document.documentElement.lang = this.$lang + const meta = [ + { + name: 'description', + content: this.$description + }, + ...(this.$page.frontmatter.meta || []) + ] + this.currentMetaTags = updateMetaTags(meta, this.currentMetaTags) } this.$watch('$page', updateMeta) updateMeta() @@ -136,15 +145,14 @@ export default { } } -function updateMetaTags (page, current) { +function updateMetaTags (meta, current) { if (current) { current.forEach(c => { document.head.removeChild(c) }) } - const data = page && page.frontmatter.meta - if (data) { - return data.map(m => { + if (meta) { + return meta.map(m => { const tag = document.createElement('meta') Object.keys(m).forEach(key => { tag.setAttribute(key, m[key]) diff --git a/lib/default-theme/NavLinks.vue b/lib/default-theme/NavLinks.vue index ef1d085057..74bc12c88a 100644 --- a/lib/default-theme/NavLinks.vue +++ b/lib/default-theme/NavLinks.vue @@ -22,15 +22,48 @@