Skip to content

Commit 9d49773

Browse files
committed
docs: add guide for writing a theme
1 parent 72c99e5 commit 9d49773

File tree

8 files changed

+272
-14
lines changed

8 files changed

+272
-14
lines changed

docs/guide/advanced/plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,6 @@ The [package.json](https://docs.npmjs.com/cli/v6/configuring-npm/package-json) f
9292
```
9393

9494
- Set `name` to follow the naming convention: `vuepress-plugin-xxx` or `@org/vuepress-plugin-xxx`.
95-
- Set `keywords` to include `'vuepress-plugin'`, so that users can search your plugin on NPM.
95+
- Set `keywords` to include `vuepress-plugin`, so that users can search your plugin on NPM.
9696
- Set `main` to the plugin entry file.
9797
- Set `files` to only publish those files inside `lib` directory.

docs/guide/advanced/theme.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,130 @@
11
# Writing a Theme
22

3-
> TODO
3+
::: tip
4+
Before reading this guide, you'd better learn the guide of [Writing a Plugin](./plugin.md) first.
5+
:::
6+
7+
A VuePress theme is a special plugin, which should satisfy the [Theme API](../../reference/theme-api.md). Like plugins, a theme can also be a *Theme Object* or a *Theme Function*.
8+
9+
<CodeGroup>
10+
<CodeGroupItem title="Theme Object" active>
11+
12+
```js
13+
const fooTheme = {
14+
name: 'vuepress-theme-foo',
15+
layouts: {
16+
Layout: path.resolve(__dirname, 'layouts/Layout.vue'),
17+
404: path.resolve(__dirname, 'layouts/404.vue'),
18+
},
19+
// ...
20+
}
21+
```
22+
23+
</CodeGroupItem>
24+
25+
<CodeGroupItem title="Theme Function">
26+
27+
```js
28+
const fooTheme = (options, app) => {
29+
return {
30+
name: 'vuepress-theme-foo',
31+
layouts: {
32+
Layout: path.resolve(__dirname, 'layouts/Layout.vue'),
33+
404: path.resolve(__dirname, 'layouts/404.vue'),
34+
},
35+
// ...
36+
}
37+
}
38+
```
39+
40+
</CodeGroupItem>
41+
</CodeGroup>
42+
43+
## Creating a Theme Package
44+
45+
The typical structure of a theme package is as follow:
46+
47+
```bash
48+
vuepress-theme-foo
49+
├─ lib
50+
│ ├─ layouts
51+
│ │ ├─ Layout.vue
52+
│ │ └─ 404.vue
53+
│ └─ index.js
54+
└─ package.json
55+
```
56+
57+
### Theme Entry
58+
59+
The `lib/index.js` file is the theme entry, which should export the theme directly:
60+
61+
<CodeGroup>
62+
<CodeGroupItem title="CJS" active>
63+
64+
```js
65+
module.export = fooTheme
66+
```
67+
68+
</CodeGroupItem>
69+
70+
<CodeGroupItem title="ESM">
71+
72+
```js
73+
export default fooTheme
74+
```
75+
76+
</CodeGroupItem>
77+
</CodeGroup>
78+
79+
::: tip
80+
Notice that the theme entry will be loaded in Node, so it should be in CommonJS format.
81+
82+
If you are using ESM format, you'll need to use [babel](https://babeljs.io/) or [typescript](https://www.typescriptlang.org/) to transpile it into CommonJS.
83+
:::
84+
85+
### package.json
86+
87+
The [package.json](https://docs.npmjs.com/cli/v6/configuring-npm/package-json) file is required to publish a package to NPM:
88+
89+
```json
90+
{
91+
"name": "vuepress-theme-foo",
92+
"version": "1.0.0",
93+
"keywords": [
94+
"vuepress-theme",
95+
],
96+
"main": "lib/index.js",
97+
"files": [
98+
"lib"
99+
]
100+
}
101+
```
102+
103+
- Set `name` to follow the naming convention: `vuepress-theme-xxx` or `@org/vuepress-theme-xxx`.
104+
- Set `keywords` to include `vuepress-theme`, so that users can search your theme on NPM.
105+
- Set `main` to the theme entry file.
106+
- Set `files` to only publish those files inside `lib` directory.
107+
108+
### Layouts
109+
110+
A theme must provide at least two layouts: `Layout` and `404`.
111+
112+
The `Layout` layout should contain the [Content](../../reference/components.md#content) component to display the markdown content:
113+
114+
```vue
115+
<template>
116+
<div>
117+
<Content />
118+
</div>
119+
</template>
120+
```
121+
122+
The `404` layout will be used for the `404.html` page:
123+
124+
```vue
125+
<template>
126+
<div>404 Not Found</div>
127+
</template>
128+
```
129+
130+
You can provide more layouts, and users can change layout via [layout](../../reference/frontmatter.md#layout) frontmatter.

docs/reference/frontmatter.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,5 @@ permalinkPattern: :year/:month/:day/:slug.html
163163
- Details:
164164

165165
Layout for the page.
166+
167+
Layouts are provided by theme. If you don't specify this frontmatter, the default layout will be used. A theme may provide other layouts, and you should refer to the theme documentation for detailed guide.

docs/reference/theme-api.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ VuePress theme also works as a plugin, so Theme API can accept all the options o
3737

3838
It also accepts a plain object, of which the key is the layout name and the value is the absolute path of the layout file.
3939

40-
A theme must have at least two layouts: `Layout` and `NotFound`.
40+
A theme must have at least two layouts: `Layout` and `404`.
4141

4242
- Example:
4343

@@ -46,7 +46,7 @@ The layout directory:
4646
```bash
4747
layouts
4848
├─ Layout.vue
49-
├─ NotFound.vue
49+
├─ 404.vue
5050
└─ FooBar.vue
5151
```
5252

@@ -64,7 +64,7 @@ Using a plain object is equivalent:
6464
module.exports = {
6565
layouts: {
6666
Layout: path.resolve(__dirname, 'path/to/layouts/Layout.vue'),
67-
NotFound: path.resolve(__dirname, 'path/to/layouts/NotFound.vue'),
67+
404: path.resolve(__dirname, 'path/to/layouts/404.vue'),
6868
FooBar: path.resolve(__dirname, 'path/to/layouts/FooBar.vue'),
6969
},
7070
}
@@ -91,9 +91,9 @@ module.exports = {
9191
// inherit the default theme
9292
extends: '@vuepress/theme-default',
9393

94-
// override the `NotFound` layout
94+
// override the `404` layout
9595
layouts: {
96-
NotFound: path.resolve(__dirname, 'path/to/NotFound.vue'),
96+
404: path.resolve(__dirname, 'path/to/404.vue'),
9797
},
9898
}
9999
```

docs/zh/guide/advanced/plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,6 @@ export default fooPlugin
9292
```
9393

9494
-`name` 按照约定命名: `vuepress-plugin-xxx``@org/vuepress-plugin-xxx`
95-
-`keywords` 中包含 `'vuepress-plugin'` ,这样用户可以在 NPM 上搜索到你的插件。
95+
-`keywords` 中包含 `vuepress-plugin` ,这样用户可以在 NPM 上搜索到你的插件。
9696
-`main` 设为插件入口文件。
9797
- 设置 `files` ,仅发布 `lib` 目录下的文件。

docs/zh/guide/advanced/theme.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,130 @@
11
# 开发主题
22

3-
> TODO
3+
::: tip
4+
在阅读该指南之前,你最好先了解一下 [开发插件](./plugin.md) 指南。
5+
:::
6+
7+
VuePress 主题是一个特殊的插件,它应该符合 [主题 API](../../reference/theme-api.md) 。和插件一样,主题可以是一个 *主题对象* 或一个 *主题函数*
8+
9+
<CodeGroup>
10+
<CodeGroupItem title="主题对象" active>
11+
12+
```js
13+
const fooTheme = {
14+
name: 'vuepress-theme-foo',
15+
layouts: {
16+
Layout: path.resolve(__dirname, 'layouts/Layout.vue'),
17+
404: path.resolve(__dirname, 'layouts/404.vue'),
18+
},
19+
// ...
20+
}
21+
```
22+
23+
</CodeGroupItem>
24+
25+
<CodeGroupItem title="主题函数">
26+
27+
```js
28+
const fooTheme = (options, app) => {
29+
return {
30+
name: 'vuepress-theme-foo',
31+
layouts: {
32+
Layout: path.resolve(__dirname, 'layouts/Layout.vue'),
33+
404: path.resolve(__dirname, 'layouts/404.vue'),
34+
},
35+
// ...
36+
}
37+
}
38+
```
39+
40+
</CodeGroupItem>
41+
</CodeGroup>
42+
43+
## 创建一个主题 Package
44+
45+
一个典型的主题 Package 的结构如下所示:
46+
47+
```bash
48+
vuepress-theme-foo
49+
├─ lib
50+
│ ├─ layouts
51+
│ │ ├─ Layout.vue
52+
│ │ └─ 404.vue
53+
│ └─ index.js
54+
└─ package.json
55+
```
56+
57+
### 主题入口
58+
59+
`lib/index.js` 文件是主题入口,它应当直接导出主题:
60+
61+
<CodeGroup>
62+
<CodeGroupItem title="CJS" active>
63+
64+
```js
65+
module.export = fooTheme
66+
```
67+
68+
</CodeGroupItem>
69+
70+
<CodeGroupItem title="ESM">
71+
72+
```js
73+
export default fooTheme
74+
```
75+
76+
</CodeGroupItem>
77+
</CodeGroup>
78+
79+
::: tip
80+
注意,主题入口会在 Node 中被加载,因此它应为 CommonJS 格式。
81+
82+
如果你使用 ESM 格式,你需要使用 [babel](https://babeljs.io/)[typescript](https://www.typescriptlang.org/) 来将它编译成 CommonJS 。
83+
:::
84+
85+
### package.json
86+
87+
为了把 Package 发布到 NPM 上,[package.json](https://docs.npmjs.com/cli/v6/configuring-npm/package-json) 文件是必需的:
88+
89+
```json
90+
{
91+
"name": "vuepress-theme-foo",
92+
"version": "1.0.0",
93+
"keywords": [
94+
"vuepress-theme",
95+
],
96+
"main": "lib/index.js",
97+
"files": [
98+
"lib"
99+
]
100+
}
101+
```
102+
103+
-`name` 按照约定命名: `vuepress-theme-xxx``@org/vuepress-theme-xxx`
104+
-`keywords` 中包含 `vuepress-theme` ,这样用户可以在 NPM 上搜索到你的主题。
105+
-`main` 设为主题入口文件。
106+
- 设置 `files` ,仅发布 `lib` 目录下的文件。
107+
108+
### 布局
109+
110+
主题必须提供至少两个布局:`Layout``404`
111+
112+
`Layout` 布局应该包含 [Content](../../reference/components.md#content) 组件来展示 Markdown 内容。
113+
114+
```vue
115+
<template>
116+
<div>
117+
<Content />
118+
</div>
119+
</template>
120+
```
121+
122+
`404` 布局会被用于 `404.html` 页面:
123+
124+
```vue
125+
<template>
126+
<div>404 Not Found</div>
127+
</template>
128+
```
129+
130+
你可以提供多个布局,用户可以通过 [layout](../../reference/frontmatter.md#layout) Frontmatter 来修改布局。

docs/zh/reference/frontmatter.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,5 @@ permalinkPattern: :year/:month/:day/:slug.html
163163
- 详情:
164164

165165
页面的布局。
166+
167+
布局是由主题提供的。如果你不指定该 Frontmatter ,则会使用默认布局。主题可能会提供其他布局,你应该参考主题文档来获取详细指引。

docs/zh/reference/theme-api.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ VuePress 主题同样是一个插件,因此主题 API 可以接收 [插件 API
3737

3838
它还可以接收一个普通对象,其键是布局名称,值是布局文件的绝对路径。
3939

40-
一个主题必须至少有两个布局: `Layout``NotFound`
40+
一个主题必须至少有两个布局: `Layout``404`
4141

4242
- 示例:
4343

@@ -46,7 +46,7 @@ VuePress 主题同样是一个插件,因此主题 API 可以接收 [插件 API
4646
```bash
4747
layouts
4848
├─ Layout.vue
49-
├─ NotFound.vue
49+
├─ 404.vue
5050
└─ FooBar.vue
5151
```
5252

@@ -64,7 +64,7 @@ module.exports = {
6464
module.exports = {
6565
layouts: {
6666
Layout: path.resolve(__dirname, 'path/to/layouts/Layout.vue'),
67-
NotFound: path.resolve(__dirname, 'path/to/layouts/NotFound.vue'),
67+
404: path.resolve(__dirname, 'path/to/layouts/404.vue'),
6868
FooBar: path.resolve(__dirname, 'path/to/layouts/FooBar.vue'),
6969
},
7070
}
@@ -91,9 +91,9 @@ module.exports = {
9191
// 继承默认主题
9292
extends: '@vuepress/theme-default',
9393

94-
// 覆盖 `NotFound` 布局
94+
// 覆盖 `404` 布局
9595
layouts: {
96-
NotFound: path.resolve(__dirname, 'path/to/NotFound.vue'),
96+
404: path.resolve(__dirname, 'path/to/404.vue'),
9797
},
9898
}
9999
```

0 commit comments

Comments
 (0)