Skip to content

Commit

Permalink
feat(plugin-register-components): add register components plugin (close
Browse files Browse the repository at this point in the history
  • Loading branch information
meteorlxy committed Apr 20, 2021
1 parent 02baabf commit 6af204d
Show file tree
Hide file tree
Showing 14 changed files with 426 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/.vuepress/configs/sidebar/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const en: SidebarConfig = {
'/reference/plugin/google-analytics.md',
'/reference/plugin/medium-zoom.md',
'/reference/plugin/nprogress.md',
'/reference/plugin/register-components.md',
],
},
{
Expand Down
1 change: 1 addition & 0 deletions docs/.vuepress/configs/sidebar/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const zh: SidebarConfig = {
'/zh/reference/plugin/google-analytics.md',
'/zh/reference/plugin/medium-zoom.md',
'/zh/reference/plugin/nprogress.md',
'/zh/reference/plugin/register-components.md',
],
},
{
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ The arguments of the function are changed, too.

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

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

#### .vuepress/theme/

Expand Down Expand Up @@ -268,7 +268,7 @@ Some major breaking changes:

- There is no **conventional theme directory structure** anymore.
- 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.
- Files in `theme/global-components/` directory will not be registered as Vue components automatically. You need to register components manually in `clientAppEnhance.{js,ts}`.
- 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}`.
- Files in `theme/layouts/` directory will not be registered as layout components automatically. You need to specify it explicitly in `layouts` option.
- Files in `theme/templates/` directory will not be used as dev / ssr template automatically.
- Always provide a theme entry file, and do not use `"main": "layouts/Layout.vue"` as the theme entry.
Expand Down
115 changes: 115 additions & 0 deletions docs/reference/plugin/register-components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# register-components

> [@vuepress/plugin-register-components](https://www.npmjs.com/package/@vuepress/plugin-register-components)
Register Vue components from component files or directory automatically.

## Options

### components

- Type: `Record<string, string>`

- Default: `{}`

- Details:

An object that defines name of components and their corresponding file path.

The key will be used as the component name, and the value is an absolute path of the component file.

If the component name from this option conflicts with [componentsDir](#componentsdir) option, this option will have a higher priority.

- Example:

```js
module.exports = {
plugins: [
[
'@vuepress/register-components',
{
components: {
FooBar: path.resolve(__dirname, './components/FooBar.vue'),
},
},
],
],
}
```

### componentsDir

- Type: `string | null`

- Default: `null`

- Details:

An absolute path of the components directory.

Files in this directory which are matched with [componentsPatterns](#componentspatterns) will be registered as Vue components automatically.

- Example:

```js
module.exports = {
plugins: [
[
'@vuepress/register-components',
{
componentsDir: path.resolve(__dirname, './components'),
},
],
],
}
```

Components directory:

```bash
components
├─ FooBar.vue
└─ Baz.vue
```

Components will be registered like this:

```js
import { defineAsyncComponent } from 'vue'

app.component(
'FooBar',
defineAsyncComponent(() => import('/path/to/components/FooBar.vue'))
)

app.component(
'Baz',
defineAsyncComponent(() => import('/path/to/components/Baz.vue'))
)
```

### componentsPatterns

- Type: `string[]`

- Default: `['**/*.vue']`

- Details:

Patterns to match component files using [globby](https://github.com/sindresorhus/globby).

The patterns are relative to [componentsDir](#componentsdir).

### getComponentName

- Type: `(filename: string) => string`

- Default: `(filename) => path.trimExt(filename.replace(/\/|\\/g, '-'))`

- Details:

A function to get component name from the filename.

It will only take effect on the files in the [componentsDir](#componentsdir) which are matched with the [componentsPatterns](#componentspatterns).

Notice that the `filename` is a filepath relative to [componentsDir](#componentsdir).
4 changes: 2 additions & 2 deletions docs/zh/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ VuePress v1 的 Stylus 调色板系统 (即 `styles/palette.styl` 和 `styles/

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

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

#### .vuepress/theme/

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

- 所谓的 **主题目录结构约定** 不再存在。
- `theme/enhanceApp.js``theme/clientAppEnhance.{js,ts}` 文件不会被隐式作为 Client App Enhance 文件。你需要在 `clientAppEnhanceFiles` Hook 中显式指定它。
- `theme/global-components/` 目录下的文件不会被自动注册为 Vue 组件。你需要在 `clientAppEnhance.{js,ts}` 中手动注册组件。
- `theme/global-components/` 目录下的文件不会被自动注册为 Vue 组件。你需要使用 `@vuepress/plugin-register-components` ,或者在 `clientAppEnhance.{js,ts}` 中手动注册组件。
- `theme/layouts/` 目录下的文件不会被自动注册为布局组件。你需要通过 `layouts` 配置项来显式指定。
- `theme/templates/` 目录下的文件不会被自动作为 dev / ssr 的模板。
- 你始终需要提供主题入口文件,并且不要使用 `"main": "layouts/Layout.vue"` 作为主题入口。
Expand Down
115 changes: 115 additions & 0 deletions docs/zh/reference/plugin/register-components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# register-components

> [@vuepress/plugin-register-components](https://www.npmjs.com/package/@vuepress/plugin-register-components)
根据组件文件或目录自动注册 Vue 组件。

## 配置项

### components

- 类型: `Record<string, string>`

- 默认值: `{}`

- 详情:

一个定义了组件名称和其对应文件路径的对象。

键会被用作组件名称,值是组件文件的绝对路径。

如果该配置项中的组件名称和 [componentsDir](#componentsdir) 配置项发生冲突,那么该配置项会有更高的优先级。

- 示例:

```js
module.exports = {
plugins: [
[
'@vuepress/register-components',
{
components: {
FooBar: path.resolve(__dirname, './components/FooBar.vue'),
},
},
],
],
}
```

### componentsDir

- 类型: `string | null`

- 默认值: `null`

- 详情:

组件目录的绝对路径。

该目录下匹配 [componentsPatterns](#componentspatterns) 的文件会被自动注册为 Vue 组件。

- 示例:

```js
module.exports = {
plugins: [
[
'@vuepress/register-components',
{
componentsDir: path.resolve(__dirname, './components'),
},
],
],
}
```

组件目录:

```bash
components
├─ FooBar.vue
└─ Baz.vue
```

组件会像这样被注册:

```js
import { defineAsyncComponent } from 'vue'

app.component(
'FooBar',
defineAsyncComponent(() => import('/path/to/components/FooBar.vue'))
)

app.component(
'Baz',
defineAsyncComponent(() => import('/path/to/components/Baz.vue'))
)
```

### componentsPatterns

- 类型: `string[]`

- 默认值: `['**/*.vue']`

- 详情:

使用 [globby](https://github.com/sindresorhus/globby) 来匹配组件文件的 Patterns 。

该 Patterns 是相对于 [componentsDir](#componentsdir) 目录的。

### getComponentName

- 类型: `(filename: string) => string`

- 默认值: `(filename) => path.trimExt(filename.replace(/\/|\\/g, '-'))`

- 详情:

用于从文件名获取对应组件名称的函数。

它只会对 [componentsDir](#componentsdir) 目录下匹配了 [componentsPatterns](#componentspatterns) 的文件生效。

注意,这里的 `filename` 是相对于 [componentsPatterns](#componentspatterns) 目录的文件路径。
39 changes: 39 additions & 0 deletions packages/@vuepress/plugin-register-components/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@vuepress/plugin-register-components",
"version": "2.0.0-beta.8",
"description": "VuePress plugin - register-components",
"keywords": [
"vuepress-plugin",
"vuepress",
"plugin",
"component"
],
"homepage": "https://github.com/vuepress",
"bugs": {
"url": "https://github.com/vuepress/vuepress-next/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vuepress/vuepress-next.git"
},
"license": "MIT",
"author": "meteorlxy",
"main": "lib/node/index.js",
"types": "lib/node/index.d.ts",
"files": [
"lib"
],
"scripts": {
"build": "tsc -b tsconfig.build.json",
"clean": "rimraf lib *.tsbuildinfo",
"copy": "cpx \"src/**/*.{css,svg}\" lib"
},
"dependencies": {
"@vuepress/core": "2.0.0-beta.8",
"@vuepress/utils": "2.0.0-beta.8",
"chokidar": "^3.5.1"
},
"publishConfig": {
"access": "public"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { globby, path } from '@vuepress/utils'
import type { RegisterComponentsPluginOptions } from './registerComponentsPlugin'

export const getComponentsFromDir = async ({
componentsDir,
componentsPatterns,
getComponentName,
}: Omit<RegisterComponentsPluginOptions, 'components'>): Promise<
Record<string, string>
> => {
if (!componentsDir) {
return {}
}

// get all matched component files
const componentsDirFiles = await globby(componentsPatterns, {
cwd: componentsDir,
})

// transform files to name => filepath map
return Object.fromEntries(
componentsDirFiles.map((filename) => [
getComponentName(filename),
path.resolve(componentsDir, filename),
])
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { registerComponentsPlugin } from './registerComponentsPlugin'

export * from './getComponentsFromDir'
export * from './prepareClientAppEnhanceFile'
export * from './registerComponentsPlugin'

export default registerComponentsPlugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { App } from '@vuepress/core'
import { getComponentsFromDir } from './getComponentsFromDir'
import type { RegisterComponentsPluginOptions } from './registerComponentsPlugin'

export const prepareClientAppEnhanceFile = async (
app: App,
options: RegisterComponentsPluginOptions,
identifier: string
): Promise<string> => {
// get components from directory
const componentsFromDir = await getComponentsFromDir(options)

// components from options will override components from dir
// if they have the same component name
const componentsMap: Record<string, string> = {
...componentsFromDir,
...options.components,
}

// client app enhance file content
const content = `\
import { defineAsyncComponent } from 'vue'
export default ({ app }) => {\
${Object.entries(componentsMap).map(
([name, filepath]) => `
app.component(${JSON.stringify(
name
)}, defineAsyncComponent(() => import(${JSON.stringify(filepath)})))`
)}
}
`

// write temp file and return the file path
return app.writeTemp(
`register-components/clientAppEnhance.${identifier}.js`,
content
)
}
Loading

0 comments on commit 6af204d

Please sign in to comment.