Skip to content

Commit 6af204d

Browse files
committed
feat(plugin-register-components): add register components plugin (close #112)
1 parent 02baabf commit 6af204d

File tree

14 files changed

+426
-4
lines changed

14 files changed

+426
-4
lines changed

Diff for: docs/.vuepress/configs/sidebar/en.ts

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export const en: SidebarConfig = {
8282
'/reference/plugin/google-analytics.md',
8383
'/reference/plugin/medium-zoom.md',
8484
'/reference/plugin/nprogress.md',
85+
'/reference/plugin/register-components.md',
8586
],
8687
},
8788
{

Diff for: docs/.vuepress/configs/sidebar/zh.ts

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export const zh: SidebarConfig = {
8585
'/zh/reference/plugin/google-analytics.md',
8686
'/zh/reference/plugin/medium-zoom.md',
8787
'/zh/reference/plugin/nprogress.md',
88+
'/zh/reference/plugin/register-components.md',
8889
],
8990
},
9091
{

Diff for: docs/guide/migration.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ The arguments of the function are changed, too.
164164

165165
Files in this directory will not be registered as Vue components automatically.
166166

167-
You need to register your components manually in `.vuepress/clientAppEnhance.{js,ts}`.
167+
You need to use `@vuepress/plugin-register-components`, or register your components manually in `.vuepress/clientAppEnhance.{js,ts}`.
168168

169169
#### .vuepress/theme/
170170

@@ -268,7 +268,7 @@ Some major breaking changes:
268268

269269
- There is no **conventional theme directory structure** anymore.
270270
- The file `theme/enhanceApp.js` or `theme/clientAppEnhance.{js,ts}` will not be used as client app enhance file implicitly. You need to specify it explicitly in `clientAppEnhanceFiles` hook.
271-
- Files in `theme/global-components/` directory will not be registered as Vue components automatically. You need to register components manually in `clientAppEnhance.{js,ts}`.
271+
- Files in `theme/global-components/` directory will not be registered as Vue components automatically. You need to use `@vuepress/plugin-register-components`, or register components manually in `clientAppEnhance.{js,ts}`.
272272
- Files in `theme/layouts/` directory will not be registered as layout components automatically. You need to specify it explicitly in `layouts` option.
273273
- Files in `theme/templates/` directory will not be used as dev / ssr template automatically.
274274
- Always provide a theme entry file, and do not use `"main": "layouts/Layout.vue"` as the theme entry.

Diff for: docs/reference/plugin/register-components.md

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# register-components
2+
3+
> [@vuepress/plugin-register-components](https://www.npmjs.com/package/@vuepress/plugin-register-components)
4+
5+
Register Vue components from component files or directory automatically.
6+
7+
## Options
8+
9+
### components
10+
11+
- Type: `Record<string, string>`
12+
13+
- Default: `{}`
14+
15+
- Details:
16+
17+
An object that defines name of components and their corresponding file path.
18+
19+
The key will be used as the component name, and the value is an absolute path of the component file.
20+
21+
If the component name from this option conflicts with [componentsDir](#componentsdir) option, this option will have a higher priority.
22+
23+
- Example:
24+
25+
```js
26+
module.exports = {
27+
plugins: [
28+
[
29+
'@vuepress/register-components',
30+
{
31+
components: {
32+
FooBar: path.resolve(__dirname, './components/FooBar.vue'),
33+
},
34+
},
35+
],
36+
],
37+
}
38+
```
39+
40+
### componentsDir
41+
42+
- Type: `string | null`
43+
44+
- Default: `null`
45+
46+
- Details:
47+
48+
An absolute path of the components directory.
49+
50+
Files in this directory which are matched with [componentsPatterns](#componentspatterns) will be registered as Vue components automatically.
51+
52+
- Example:
53+
54+
```js
55+
module.exports = {
56+
plugins: [
57+
[
58+
'@vuepress/register-components',
59+
{
60+
componentsDir: path.resolve(__dirname, './components'),
61+
},
62+
],
63+
],
64+
}
65+
```
66+
67+
Components directory:
68+
69+
```bash
70+
components
71+
├─ FooBar.vue
72+
└─ Baz.vue
73+
```
74+
75+
Components will be registered like this:
76+
77+
```js
78+
import { defineAsyncComponent } from 'vue'
79+
80+
app.component(
81+
'FooBar',
82+
defineAsyncComponent(() => import('/path/to/components/FooBar.vue'))
83+
)
84+
85+
app.component(
86+
'Baz',
87+
defineAsyncComponent(() => import('/path/to/components/Baz.vue'))
88+
)
89+
```
90+
91+
### componentsPatterns
92+
93+
- Type: `string[]`
94+
95+
- Default: `['**/*.vue']`
96+
97+
- Details:
98+
99+
Patterns to match component files using [globby](https://github.com/sindresorhus/globby).
100+
101+
The patterns are relative to [componentsDir](#componentsdir).
102+
103+
### getComponentName
104+
105+
- Type: `(filename: string) => string`
106+
107+
- Default: `(filename) => path.trimExt(filename.replace(/\/|\\/g, '-'))`
108+
109+
- Details:
110+
111+
A function to get component name from the filename.
112+
113+
It will only take effect on the files in the [componentsDir](#componentsdir) which are matched with the [componentsPatterns](#componentspatterns).
114+
115+
Notice that the `filename` is a filepath relative to [componentsDir](#componentsdir).

Diff for: docs/zh/guide/migration.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ VuePress v1 的 Stylus 调色板系统 (即 `styles/palette.styl` 和 `styles/
164164

165165
在该目录下的文件不会被自动注册为 Vue 组件。
166166

167-
你需要在 `.vuepress/clientAppEnhance.{js,ts}` 中手动注册你的组件。
167+
你需要使用 `@vuepress/plugin-register-components` ,或者在 `.vuepress/clientAppEnhance.{js,ts}` 中手动注册你的组件。
168168

169169
#### .vuepress/theme/
170170

@@ -268,7 +268,7 @@ v1 的主题和插件和 v2 并不兼容。
268268

269269
- 所谓的 **主题目录结构约定** 不再存在。
270270
- `theme/enhanceApp.js``theme/clientAppEnhance.{js,ts}` 文件不会被隐式作为 Client App Enhance 文件。你需要在 `clientAppEnhanceFiles` Hook 中显式指定它。
271-
- `theme/global-components/` 目录下的文件不会被自动注册为 Vue 组件。你需要在 `clientAppEnhance.{js,ts}` 中手动注册组件。
271+
- `theme/global-components/` 目录下的文件不会被自动注册为 Vue 组件。你需要使用 `@vuepress/plugin-register-components` ,或者在 `clientAppEnhance.{js,ts}` 中手动注册组件。
272272
- `theme/layouts/` 目录下的文件不会被自动注册为布局组件。你需要通过 `layouts` 配置项来显式指定。
273273
- `theme/templates/` 目录下的文件不会被自动作为 dev / ssr 的模板。
274274
- 你始终需要提供主题入口文件,并且不要使用 `"main": "layouts/Layout.vue"` 作为主题入口。

Diff for: docs/zh/reference/plugin/register-components.md

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# register-components
2+
3+
> [@vuepress/plugin-register-components](https://www.npmjs.com/package/@vuepress/plugin-register-components)
4+
5+
根据组件文件或目录自动注册 Vue 组件。
6+
7+
## 配置项
8+
9+
### components
10+
11+
- 类型: `Record<string, string>`
12+
13+
- 默认值: `{}`
14+
15+
- 详情:
16+
17+
一个定义了组件名称和其对应文件路径的对象。
18+
19+
键会被用作组件名称,值是组件文件的绝对路径。
20+
21+
如果该配置项中的组件名称和 [componentsDir](#componentsdir) 配置项发生冲突,那么该配置项会有更高的优先级。
22+
23+
- 示例:
24+
25+
```js
26+
module.exports = {
27+
plugins: [
28+
[
29+
'@vuepress/register-components',
30+
{
31+
components: {
32+
FooBar: path.resolve(__dirname, './components/FooBar.vue'),
33+
},
34+
},
35+
],
36+
],
37+
}
38+
```
39+
40+
### componentsDir
41+
42+
- 类型: `string | null`
43+
44+
- 默认值: `null`
45+
46+
- 详情:
47+
48+
组件目录的绝对路径。
49+
50+
该目录下匹配 [componentsPatterns](#componentspatterns) 的文件会被自动注册为 Vue 组件。
51+
52+
- 示例:
53+
54+
```js
55+
module.exports = {
56+
plugins: [
57+
[
58+
'@vuepress/register-components',
59+
{
60+
componentsDir: path.resolve(__dirname, './components'),
61+
},
62+
],
63+
],
64+
}
65+
```
66+
67+
组件目录:
68+
69+
```bash
70+
components
71+
├─ FooBar.vue
72+
└─ Baz.vue
73+
```
74+
75+
组件会像这样被注册:
76+
77+
```js
78+
import { defineAsyncComponent } from 'vue'
79+
80+
app.component(
81+
'FooBar',
82+
defineAsyncComponent(() => import('/path/to/components/FooBar.vue'))
83+
)
84+
85+
app.component(
86+
'Baz',
87+
defineAsyncComponent(() => import('/path/to/components/Baz.vue'))
88+
)
89+
```
90+
91+
### componentsPatterns
92+
93+
- 类型: `string[]`
94+
95+
- 默认值: `['**/*.vue']`
96+
97+
- 详情:
98+
99+
使用 [globby](https://github.com/sindresorhus/globby) 来匹配组件文件的 Patterns 。
100+
101+
该 Patterns 是相对于 [componentsDir](#componentsdir) 目录的。
102+
103+
### getComponentName
104+
105+
- 类型: `(filename: string) => string`
106+
107+
- 默认值: `(filename) => path.trimExt(filename.replace(/\/|\\/g, '-'))`
108+
109+
- 详情:
110+
111+
用于从文件名获取对应组件名称的函数。
112+
113+
它只会对 [componentsDir](#componentsdir) 目录下匹配了 [componentsPatterns](#componentspatterns) 的文件生效。
114+
115+
注意,这里的 `filename` 是相对于 [componentsPatterns](#componentspatterns) 目录的文件路径。
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "@vuepress/plugin-register-components",
3+
"version": "2.0.0-beta.8",
4+
"description": "VuePress plugin - register-components",
5+
"keywords": [
6+
"vuepress-plugin",
7+
"vuepress",
8+
"plugin",
9+
"component"
10+
],
11+
"homepage": "https://github.com/vuepress",
12+
"bugs": {
13+
"url": "https://github.com/vuepress/vuepress-next/issues"
14+
},
15+
"repository": {
16+
"type": "git",
17+
"url": "git+https://github.com/vuepress/vuepress-next.git"
18+
},
19+
"license": "MIT",
20+
"author": "meteorlxy",
21+
"main": "lib/node/index.js",
22+
"types": "lib/node/index.d.ts",
23+
"files": [
24+
"lib"
25+
],
26+
"scripts": {
27+
"build": "tsc -b tsconfig.build.json",
28+
"clean": "rimraf lib *.tsbuildinfo",
29+
"copy": "cpx \"src/**/*.{css,svg}\" lib"
30+
},
31+
"dependencies": {
32+
"@vuepress/core": "2.0.0-beta.8",
33+
"@vuepress/utils": "2.0.0-beta.8",
34+
"chokidar": "^3.5.1"
35+
},
36+
"publishConfig": {
37+
"access": "public"
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { globby, path } from '@vuepress/utils'
2+
import type { RegisterComponentsPluginOptions } from './registerComponentsPlugin'
3+
4+
export const getComponentsFromDir = async ({
5+
componentsDir,
6+
componentsPatterns,
7+
getComponentName,
8+
}: Omit<RegisterComponentsPluginOptions, 'components'>): Promise<
9+
Record<string, string>
10+
> => {
11+
if (!componentsDir) {
12+
return {}
13+
}
14+
15+
// get all matched component files
16+
const componentsDirFiles = await globby(componentsPatterns, {
17+
cwd: componentsDir,
18+
})
19+
20+
// transform files to name => filepath map
21+
return Object.fromEntries(
22+
componentsDirFiles.map((filename) => [
23+
getComponentName(filename),
24+
path.resolve(componentsDir, filename),
25+
])
26+
)
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { registerComponentsPlugin } from './registerComponentsPlugin'
2+
3+
export * from './getComponentsFromDir'
4+
export * from './prepareClientAppEnhanceFile'
5+
export * from './registerComponentsPlugin'
6+
7+
export default registerComponentsPlugin
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { App } from '@vuepress/core'
2+
import { getComponentsFromDir } from './getComponentsFromDir'
3+
import type { RegisterComponentsPluginOptions } from './registerComponentsPlugin'
4+
5+
export const prepareClientAppEnhanceFile = async (
6+
app: App,
7+
options: RegisterComponentsPluginOptions,
8+
identifier: string
9+
): Promise<string> => {
10+
// get components from directory
11+
const componentsFromDir = await getComponentsFromDir(options)
12+
13+
// components from options will override components from dir
14+
// if they have the same component name
15+
const componentsMap: Record<string, string> = {
16+
...componentsFromDir,
17+
...options.components,
18+
}
19+
20+
// client app enhance file content
21+
const content = `\
22+
import { defineAsyncComponent } from 'vue'
23+
24+
export default ({ app }) => {\
25+
${Object.entries(componentsMap).map(
26+
([name, filepath]) => `
27+
app.component(${JSON.stringify(
28+
name
29+
)}, defineAsyncComponent(() => import(${JSON.stringify(filepath)})))`
30+
)}
31+
}
32+
`
33+
34+
// write temp file and return the file path
35+
return app.writeTemp(
36+
`register-components/clientAppEnhance.${identifier}.js`,
37+
content
38+
)
39+
}

0 commit comments

Comments
 (0)