From c52cf06aa7444a51dd75671873d20e3a17fea453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=87=E7=BA=AF?= Date: Mon, 8 Mar 2021 20:45:57 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=8F=92=E4=BB=B6=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vuepress/configs/sidebar/en.ts | 3 +- docs/.vuepress/configs/sidebar/zh.ts | 3 +- docs/.vuepress/public/manifest.webmanifest | 4 +- docs/guide/directory-structure.md | 4 +- docs/reference/plugin/api.md | 1 - docs/reference/plugin/dev/README.md | 43 ++ docs/reference/plugin/dev/api.md | 494 +++++++++++++++++++++ docs/zh/guide/directory-structure.md | 2 +- docs/zh/reference/plugin/api.md | 1 - docs/zh/reference/plugin/dev/README.md | 43 ++ docs/zh/reference/plugin/dev/api.md | 494 +++++++++++++++++++++ packages/fes-template/.env | 3 +- 12 files changed, 1084 insertions(+), 11 deletions(-) delete mode 100644 docs/reference/plugin/api.md create mode 100644 docs/reference/plugin/dev/README.md create mode 100644 docs/reference/plugin/dev/api.md delete mode 100644 docs/zh/reference/plugin/api.md create mode 100644 docs/zh/reference/plugin/dev/README.md create mode 100644 docs/zh/reference/plugin/dev/api.md diff --git a/docs/.vuepress/configs/sidebar/en.ts b/docs/.vuepress/configs/sidebar/en.ts index 75ca9764..45b97a43 100644 --- a/docs/.vuepress/configs/sidebar/en.ts +++ b/docs/.vuepress/configs/sidebar/en.ts @@ -66,7 +66,8 @@ export const en: SidebarConfig = { isGroup: true, text: '插件开发', children: [ - '/reference/plugin/api.md' + '/reference/plugin/dev/README.md', + '/reference/plugin/dev/api.md' ], }, ], diff --git a/docs/.vuepress/configs/sidebar/zh.ts b/docs/.vuepress/configs/sidebar/zh.ts index a264f047..eb5967d6 100644 --- a/docs/.vuepress/configs/sidebar/zh.ts +++ b/docs/.vuepress/configs/sidebar/zh.ts @@ -66,7 +66,8 @@ export const zh: SidebarConfig = { isGroup: true, text: '插件开发', children: [ - '/zh/reference/plugin/api.md' + '/zh/reference/plugin/dev/README.md', + '/zh/reference/plugin/dev/api.md' ], }, ], diff --git a/docs/.vuepress/public/manifest.webmanifest b/docs/.vuepress/public/manifest.webmanifest index 7c3e03f4..2f8809d5 100644 --- a/docs/.vuepress/public/manifest.webmanifest +++ b/docs/.vuepress/public/manifest.webmanifest @@ -2,13 +2,13 @@ "name": "Fes.js", "short_name": "Fes", "description": "一套好用的前端解决方案", - "start_url": "/index.html", + "start_url": "./index.html", "display": "standalone", "background_color": "#fff", "theme_color": "#3eaf7c", "icons": [ { - "src": "/hero.png", + "src": "./hero.png", "sizes": "192x192", "type": "image/png" } diff --git a/docs/guide/directory-structure.md b/docs/guide/directory-structure.md index 6593f105..e23c28ad 100644 --- a/docs/guide/directory-structure.md +++ b/docs/guide/directory-structure.md @@ -21,7 +21,7 @@ fes-template ### 根目录 #### package.json -包含插件和插件集,以 `@fesjs/preset-`、`@fesjs/plugin-`、`@webank/fes-preset-`、`@webank/fes-plugin-` `fes-preset-` 和 `fes-plugin-` 开头的依赖会被自动注册为插件或插件集。 +包含插件和插件集,以 `@fesjs/preset-`、`@fesjs/plugin-`、`@webank/fes-preset-`、`@webank/fes-plugin-`、`fes-preset-` 和 `fes-plugin-` 开头的依赖会被自动注册为插件或插件集。 #### tsconfig.json 解决 `@fesjs/fes` 和使用 `@` 的 API 提示 @@ -64,7 +64,7 @@ mock 数据的配置文件。 不要提交 `.fes` 目录到 `git` 仓库,他们会在 `fes dev` 和 `fes build` 时被删除并重新生成。 ::: #### pages 目录 -所有路由组件存放在这里。 +所有路由组件文件存放在这里。 #### app.js 运行时配置文件,可以在这里扩展运行时的能力,比如修改路由等。 \ No newline at end of file diff --git a/docs/reference/plugin/api.md b/docs/reference/plugin/api.md deleted file mode 100644 index 52839bf2..00000000 --- a/docs/reference/plugin/api.md +++ /dev/null @@ -1 +0,0 @@ -# 插件API \ No newline at end of file diff --git a/docs/reference/plugin/dev/README.md b/docs/reference/plugin/dev/README.md new file mode 100644 index 00000000..964ea9c4 --- /dev/null +++ b/docs/reference/plugin/dev/README.md @@ -0,0 +1,43 @@ +# 插件介绍 + +## 开始 +一个插件是一个 `npm` 包,它能够为 Fes.js 创建的项目添加额外的功能,这些功能包括: + +- 项目的 webpack 配置。 +- 修改项目的 babel 配置。 +- 添加新的 fes 命令 - 例如 `@fes/plugin-jest` 添加了 `fes test` 命令,允许开发者运行单元测试。 +- 集成 Vue 的插件。 +- 修改路由配置 +- 提供运行时 API +- ... + +插件的入口是一个函数,函数会以 API 对象作为第一个参数: +```js +export default (api)=>{ + api.describe({ + key: 'esbuild', + config: { + schema(joi) { + return joi.object(); + }, + default: {} + }, + enableBy: api.EnableBy.config, + }); +} +``` +API 对象是构建流程管理 Service 类的实例,api 提供一些有用的方法帮助你开发插件。 + +`api.describe`用来描述插件: +- **key**, 插件的 `key`,可以理解为插件的名称,在 `.fes.js` 中用 `key` 配置此插件。 +- **config**,插件的配置信息: + - schema,定义配置的类型 + - default,默认配置 +- **enableBy**, 是否开启插件,可配置某些场景下禁用插件。 + + +## 发布到 npm + +以 `@fesjs/preset-`、`@fesjs/plugin-`、`@webank/fes-preset-`、`@webank/fes-plugin-`、`fes-preset-` 和 `fes-plugin-` 开头的依赖会被 Fes.js 自动注册为插件或插件集。 + +所以编写好的插件想发布到 npm 供其他人使用,包名必须是 `fes-preset-` 和 `fes-plugin-` 开头。 \ No newline at end of file diff --git a/docs/reference/plugin/dev/api.md b/docs/reference/plugin/dev/api.md new file mode 100644 index 00000000..802041da --- /dev/null +++ b/docs/reference/plugin/dev/api.md @@ -0,0 +1,494 @@ +# 插件 API + +## 属性 + +### api.paths + +一些关键的路径: +- cwd,执行命令的绝对路径 +- absNodeModulesPath,nodeModule的绝对路径 +- absOutputPath,输出 `build` 产物的绝对路径 +- absSrcPath,`src` 目录的绝对路径 +- absPagesPath,`pages`目录的绝对路径 +- absTmpPath,`.fes`临时文件目录的绝对路径 + +### api.cwd +执行命令的绝对路径 + +### api.pkg +`package.json`的内容 + +### api.configInstance +`config`实例 + +### userConfig +用户配置 + +### config +插件配置可被修改,此为最终的配置 + +### env +process.env + +### args +环境变量 + +## 核心方法 + +### describe +注册阶段执行,用于描述插件或插件集的 id、key、配置信息、启用方式等。 + +用法:**describe({ id?: string, key?: string, config?: { default, schema, onChange } }, enableBy?)** + +例如: +```js + api.describe({ + key: 'esbuild', + config: { + schema(joi) { + return joi.object(); + }, + default: {} + }, + enableBy: api.EnableBy.config, +}); +``` +注: + +- `config.default` 为配置的默认值,用户没有配置时取这个 +- `config.schema` 用于声明配置的类型,基于 [joi](https://hapi.dev/module/joi),如果你希望用户进行配置,这个是必须的,否则用户的配置无效 +- `config.onChange` 是 `dev` 阶段配置被修改后的处理机制,默认会重启 dev 进程,也可以修改为 api.ConfigChangeType.regenerateTmpFiles 只重新生成临时文件,还可以通过函数的格式自定义 +- `enableBy` 为启用方式,默认是注册启用,可更改为 `api.EnableBy.config`,还可以用自定义函数的方式决定其启用时机(动态生效) + + + +### applyPlugins + +取得 register 注册的 hooks 执行后的数据。 + +用法:**applyPlugins({ key: string, type: api.ApplyPluginsType, initialValue?: any, args?: any })** + +参数: +- key +- type, hook的类型。 +- initialValue, 初始值。 +- args,参数,hook函数执行时,args会作为参数传入。 + +例如: +```js +const foo = await api.applyPlugins({ + key: 'foo', + type: api.ApplyPluginsType.add, + initialValue: [], +}); +console.log(foo); // ['a', 'b'] +``` + +#### api.ApplyPluginsType + +编译时插件hook执行类型,enum 类型,包含三个属性: + +- compose,用于合并执行多个函数,函数可决定前序函数的执行时机 +- modify,用于修改值 +- event,用于执行事件,前面没有依赖关系 + +### registerCommand + +注册命令,基于 [commander](https://github.com/tj/commander.js/) 实现的机制。 + +用法:**registerCommand({ command: string, description: string, fn: Function, options?: Object })** + +参数: +- command +- description,描述文字,输入 `--help` 会打印 +- fn,命令执行的函数,参数有: + - rawArgv,原始参数 + - args,参数 + - options,执行命令时附带的的参数配置 + - program,commander对象 +- options,参数配置,基于 [commander](https://github.com/tj/commander.js/) 。 + +例如: +```js +api.registerCommand({ + command: 'webpack', + description: 'inspect webpack configurations', + options: [{ + name: '--rule ', + description: 'inspect a specific module rule' + }, { + name: '--plugin ', + description: 'inspect a specific plugin' + }, { + name: '--rules', + description: 'list all module rule names' + }, { + name: '--plugins', + description: 'list all plugin names' + }, { + name: '--verbose', + description: 'show full function definitions in output' + }], + async fn({ rawArgv, args, options, program}) { + } +}) +``` +当项目引入此插件后,使用: +```bash +fes webpack +``` + +### registerMethod + +往 `api` 上注册方法。可以是 `api.register()` 的快捷使用方式,便于调用;也可以不是,如果有提供 `fn`,则执行 `fn` 定义的函数。 + +用法:**registerMethod({ name: string, fn?: Function, exitsError?: boolean })** + +例如: +```js + api.registerMethod({ + name: 'writeTmpFile', + fn({ + path, + content + }) { + assert( + api.stage >= api.ServiceStage.pluginReady, + 'api.writeTmpFile() should not execute in register stage.' + ); + const absPath = join(api.paths.absTmpPath, path); + api.utils.mkdirp.sync(dirname(absPath)); + if (!existsSync(absPath) || readFileSync(absPath, 'utf-8') !== content) { + writeFileSync(absPath, content, 'utf-8'); + } + } +}); +``` + +### registerPresets + +注册插件集,参数为路径数组。 + +用法:**registerPresets(presets: string[])** + +例如: +```js +api.registerPresets([ + { id: 'preset_2', key: 'preset2', apply: () => () => {} }, + require.resolve('./preset_3'), +]); +``` + +### registerPlugins + +注册插件,参数为路径数组。 + +用法:**registerPlugins(plugins: string[])** + +例如: +```js +api.registerPlugins([ + { id: 'preset_2', key: 'preset2', apply: () => () => {} }, + require.resolve('./preset_3'), +]); +``` + +### hasPlugins +判断是否有注册某个插件,插件的 id 规则: +- id 默认为包名 +- 内置插件以 `@@` 为前缀,比如 `@@/registerMethod` + +用法:**hasPlugins(pluginIds: string[])** + +例如 +```js +// 判断是否有注册 @fesjs/plugin-locale +api.hasPlugins(['@fesjs/plugin-locale']); +``` + +::: tip +如果在注册阶段使用,只能判断在他之前是否有注册某个插件。 +::: + +### hasPresets +判断是否有注册某个插件集。 + +用法:**hasPresets(presetIds: string[])** + +例如 +```js +// 判断是否有注册 +api.hasPlugins(['@fesjs/preset-xxx']); +``` + +::: tip +如果在注册阶段使用,只能判断在他之前是否有注册某个插件集。 +::: + +## 扩展方法 + +通过 api.registerMethod() 扩展的方法。 + +### onStart +在命令注册函数执行前触发。可以使用 config 和 paths。 + +### onExit +dev 退出时触发。 + +### onGenerateFiles +生成临时文件,触发时机在 webpack 编译之前。 + +### addPluginExports +把插件需要导出的运行时 API 写入`@fesjs/fes`。 +```js +api.addPluginExports(() => [ + { + specifiers: ['access', 'useAccess'], + source: absoluteFilePath + } +]); +``` +这样用户使用时: +```js +import { access, useAccess } from '@fesjs/fes'; +``` + +### addRuntimePlugin +添加运行时插件,返回值格式为表示文件路径的字符串。Fes.js 会把 + +例如: +```js +api.addRuntimePlugin(() => join(__dirname, './runtime')); +``` + +### addRuntimePluginKey +添加运行时插件的 key,返回值格式为字符串。 + +例如: +```js +api.addRuntimePluginKey(() => 'some'); +``` + +### addEntryImportsAhead +在入口文件现有 import 的前面添加 import。 + +例如: +```js +api.addEntryImportsAhead(() => [{ source: 'anypackage' }]); +``` + +### addEntryImports +在入口文件现有 import 的后面添加 import。 + +例如: +```js +api.addEntryImport(() => { + return [ + { + source: '/modulePath/xxx.js', + specifier: 'moduleName', + } + ] +}); +``` + +### addEntryCodeAhead +在入口文件最前面(import 之后)添加代码。 + +例如: +```js +api.addEntryCodeAhead( + () => `${globalCSSFile + .map(file => `require('${winPath(relative(absTmpPath, file))}');`) + .join('')}` + +``` + +### addEntryCode +在入口文件最后添加代码。 + +例如: +```js +api.addEntryCode(() => { + return `console.log('works!')` +}) +``` + +### addBeforeMiddlewares +添加在 `webpack compiler` 中间件之前的中间件,返回值格式为 `express` 中间件。 + +例如: +```js +api.addBeforeMiddlewares(() => { + return (req, res, next) => { + if (false) { + res.end('end'); + } else { + next(); + } + }; +}); +``` + +### addMiddlewares +添加在 `webpack compiler` 中间件之后的中间件,返回值格式为 `express` 中间件。 + +### modifyRoutes + +修改路由。 + +例如: +```js +// 把BaseLayout插入到路由配置中,作为根路由 +api.modifyRoutes(routes => [ + { + path: '/', + component: winPath( + join(api.paths.absTmpPath || '', absFilePath) + ), + children: routes + } +]); +``` + +### modifyBundleConfigOpts +修改获取 bundleConfig 的函数参数。 + +例如: +```js +api.modifyBundleConfigOpts(memo => { + memo.miniCSSExtractPluginPath = require.resolve('mini-css-extract-plugin'); + memo.miniCSSExtractPluginLoaderPath = require.resolve( + 'mini-css-extract-plugin/dist/loader', + ); + return memo; +}); + +``` + +### modifyBundleConfig +修改 bundle 配置。 + +```js +api.modifyBundleConfig((bundleConfig) => { + // do something + return bundleConfig; +}); +``` + +### modifyBabelOpts +修改 babel 配置项。 + +例如: +```js +api.modifyBabelOpts((babelOpts) => { + if (api.config.babelPluginImport) { + api.config.babelPluginImport.forEach((config) => { + babelOpts.plugins.push(['import', config]); + }); + } + return babelOpts; +}); +``` + +### modifyBabelPresetOpts +修改 babel 插件的配置。 + +例如: +```js +api.modifyBabelPresetOpts(opts => { + return { + ...opts, + import: (opts.import || []).concat([ + { libraryName: 'ant-design-vue', libraryDirectory: 'es', style: true }, + ]), + }; +}); +``` + +### modifyPaths +修改 paths 对象。 + + +### modifyConfig +修改最终配置。 + +例如: +```js +api.modifyConfig((memo) => { + return { + ...memo, + ...defaultOptions, + }; +}); + +``` + +### chainWebpack +通过 [webpack-chain] 的方式修改 webpack 配置。 + +例如: +```js +api.chainWebpack((memo) => { + memo.resolve.alias.set('vue-i18n', 'vue-i18n/dist/vue-i18n.esm-bundler.js'); +}); +``` + +### addTmpGenerateWatcherPaths +添加重新临时文件生成的监听路径。 + +例如: +```js +api.addTmpGenerateWatcherPaths(() => [ + './app.js', +]); +``` + +### writeTmpFile +写临时文件。 + +例如: +```js +api.writeTmpFile({ + path: absoluteFilePath, + content: Mustache.render( + readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'), + { + REPLACE_ROLES: JSON.stringify(roles) + } + ) +}); +``` + +参数: + +- path:相对于临时文件夹的路径 +- content:文件内容 + +::: tip +不能在注册阶段使用,通常放在 api.onGenerateFiles() 里,这样能在需要时重新生成临时文件 +临时文件的写入做了缓存处理,如果内容一致,不会做写的操作,以减少触发 webpack 的重新编译 +::: + +### copyTmpFiles +批量写临时文件。 + +例如: +```js + api.copyTmpFiles({ + namespace, + path: join(__dirname, 'runtime'), + ignore: ['.tpl'] +}); +``` + +参数: + +- namespace:复制到临时文件夹下的目标目录 +- path:需要复制的文件目录 +- ignore:需要排除的文件 + +::: tip +不能在注册阶段使用,通常放在 api.onGenerateFiles() 里,这样能在需要时重新生成临时文件 +临时文件的写入做了缓存处理,如果内容一致,不会做写的操作,以减少触发 `webpack` 的重新编译 +::: \ No newline at end of file diff --git a/docs/zh/guide/directory-structure.md b/docs/zh/guide/directory-structure.md index 684e5878..e23c28ad 100644 --- a/docs/zh/guide/directory-structure.md +++ b/docs/zh/guide/directory-structure.md @@ -21,7 +21,7 @@ fes-template ### 根目录 #### package.json -包含插件和插件集,以 `@fesjs/preset-`、`@fesjs/plugin-`、`@webank/fes-preset-`、`@webank/fes-plugin-` `fes-preset-` 和 `fes-plugin-` 开头的依赖会被自动注册为插件或插件集。 +包含插件和插件集,以 `@fesjs/preset-`、`@fesjs/plugin-`、`@webank/fes-preset-`、`@webank/fes-plugin-`、`fes-preset-` 和 `fes-plugin-` 开头的依赖会被自动注册为插件或插件集。 #### tsconfig.json 解决 `@fesjs/fes` 和使用 `@` 的 API 提示 diff --git a/docs/zh/reference/plugin/api.md b/docs/zh/reference/plugin/api.md deleted file mode 100644 index 52839bf2..00000000 --- a/docs/zh/reference/plugin/api.md +++ /dev/null @@ -1 +0,0 @@ -# 插件API \ No newline at end of file diff --git a/docs/zh/reference/plugin/dev/README.md b/docs/zh/reference/plugin/dev/README.md new file mode 100644 index 00000000..964ea9c4 --- /dev/null +++ b/docs/zh/reference/plugin/dev/README.md @@ -0,0 +1,43 @@ +# 插件介绍 + +## 开始 +一个插件是一个 `npm` 包,它能够为 Fes.js 创建的项目添加额外的功能,这些功能包括: + +- 项目的 webpack 配置。 +- 修改项目的 babel 配置。 +- 添加新的 fes 命令 - 例如 `@fes/plugin-jest` 添加了 `fes test` 命令,允许开发者运行单元测试。 +- 集成 Vue 的插件。 +- 修改路由配置 +- 提供运行时 API +- ... + +插件的入口是一个函数,函数会以 API 对象作为第一个参数: +```js +export default (api)=>{ + api.describe({ + key: 'esbuild', + config: { + schema(joi) { + return joi.object(); + }, + default: {} + }, + enableBy: api.EnableBy.config, + }); +} +``` +API 对象是构建流程管理 Service 类的实例,api 提供一些有用的方法帮助你开发插件。 + +`api.describe`用来描述插件: +- **key**, 插件的 `key`,可以理解为插件的名称,在 `.fes.js` 中用 `key` 配置此插件。 +- **config**,插件的配置信息: + - schema,定义配置的类型 + - default,默认配置 +- **enableBy**, 是否开启插件,可配置某些场景下禁用插件。 + + +## 发布到 npm + +以 `@fesjs/preset-`、`@fesjs/plugin-`、`@webank/fes-preset-`、`@webank/fes-plugin-`、`fes-preset-` 和 `fes-plugin-` 开头的依赖会被 Fes.js 自动注册为插件或插件集。 + +所以编写好的插件想发布到 npm 供其他人使用,包名必须是 `fes-preset-` 和 `fes-plugin-` 开头。 \ No newline at end of file diff --git a/docs/zh/reference/plugin/dev/api.md b/docs/zh/reference/plugin/dev/api.md new file mode 100644 index 00000000..802041da --- /dev/null +++ b/docs/zh/reference/plugin/dev/api.md @@ -0,0 +1,494 @@ +# 插件 API + +## 属性 + +### api.paths + +一些关键的路径: +- cwd,执行命令的绝对路径 +- absNodeModulesPath,nodeModule的绝对路径 +- absOutputPath,输出 `build` 产物的绝对路径 +- absSrcPath,`src` 目录的绝对路径 +- absPagesPath,`pages`目录的绝对路径 +- absTmpPath,`.fes`临时文件目录的绝对路径 + +### api.cwd +执行命令的绝对路径 + +### api.pkg +`package.json`的内容 + +### api.configInstance +`config`实例 + +### userConfig +用户配置 + +### config +插件配置可被修改,此为最终的配置 + +### env +process.env + +### args +环境变量 + +## 核心方法 + +### describe +注册阶段执行,用于描述插件或插件集的 id、key、配置信息、启用方式等。 + +用法:**describe({ id?: string, key?: string, config?: { default, schema, onChange } }, enableBy?)** + +例如: +```js + api.describe({ + key: 'esbuild', + config: { + schema(joi) { + return joi.object(); + }, + default: {} + }, + enableBy: api.EnableBy.config, +}); +``` +注: + +- `config.default` 为配置的默认值,用户没有配置时取这个 +- `config.schema` 用于声明配置的类型,基于 [joi](https://hapi.dev/module/joi),如果你希望用户进行配置,这个是必须的,否则用户的配置无效 +- `config.onChange` 是 `dev` 阶段配置被修改后的处理机制,默认会重启 dev 进程,也可以修改为 api.ConfigChangeType.regenerateTmpFiles 只重新生成临时文件,还可以通过函数的格式自定义 +- `enableBy` 为启用方式,默认是注册启用,可更改为 `api.EnableBy.config`,还可以用自定义函数的方式决定其启用时机(动态生效) + + + +### applyPlugins + +取得 register 注册的 hooks 执行后的数据。 + +用法:**applyPlugins({ key: string, type: api.ApplyPluginsType, initialValue?: any, args?: any })** + +参数: +- key +- type, hook的类型。 +- initialValue, 初始值。 +- args,参数,hook函数执行时,args会作为参数传入。 + +例如: +```js +const foo = await api.applyPlugins({ + key: 'foo', + type: api.ApplyPluginsType.add, + initialValue: [], +}); +console.log(foo); // ['a', 'b'] +``` + +#### api.ApplyPluginsType + +编译时插件hook执行类型,enum 类型,包含三个属性: + +- compose,用于合并执行多个函数,函数可决定前序函数的执行时机 +- modify,用于修改值 +- event,用于执行事件,前面没有依赖关系 + +### registerCommand + +注册命令,基于 [commander](https://github.com/tj/commander.js/) 实现的机制。 + +用法:**registerCommand({ command: string, description: string, fn: Function, options?: Object })** + +参数: +- command +- description,描述文字,输入 `--help` 会打印 +- fn,命令执行的函数,参数有: + - rawArgv,原始参数 + - args,参数 + - options,执行命令时附带的的参数配置 + - program,commander对象 +- options,参数配置,基于 [commander](https://github.com/tj/commander.js/) 。 + +例如: +```js +api.registerCommand({ + command: 'webpack', + description: 'inspect webpack configurations', + options: [{ + name: '--rule ', + description: 'inspect a specific module rule' + }, { + name: '--plugin ', + description: 'inspect a specific plugin' + }, { + name: '--rules', + description: 'list all module rule names' + }, { + name: '--plugins', + description: 'list all plugin names' + }, { + name: '--verbose', + description: 'show full function definitions in output' + }], + async fn({ rawArgv, args, options, program}) { + } +}) +``` +当项目引入此插件后,使用: +```bash +fes webpack +``` + +### registerMethod + +往 `api` 上注册方法。可以是 `api.register()` 的快捷使用方式,便于调用;也可以不是,如果有提供 `fn`,则执行 `fn` 定义的函数。 + +用法:**registerMethod({ name: string, fn?: Function, exitsError?: boolean })** + +例如: +```js + api.registerMethod({ + name: 'writeTmpFile', + fn({ + path, + content + }) { + assert( + api.stage >= api.ServiceStage.pluginReady, + 'api.writeTmpFile() should not execute in register stage.' + ); + const absPath = join(api.paths.absTmpPath, path); + api.utils.mkdirp.sync(dirname(absPath)); + if (!existsSync(absPath) || readFileSync(absPath, 'utf-8') !== content) { + writeFileSync(absPath, content, 'utf-8'); + } + } +}); +``` + +### registerPresets + +注册插件集,参数为路径数组。 + +用法:**registerPresets(presets: string[])** + +例如: +```js +api.registerPresets([ + { id: 'preset_2', key: 'preset2', apply: () => () => {} }, + require.resolve('./preset_3'), +]); +``` + +### registerPlugins + +注册插件,参数为路径数组。 + +用法:**registerPlugins(plugins: string[])** + +例如: +```js +api.registerPlugins([ + { id: 'preset_2', key: 'preset2', apply: () => () => {} }, + require.resolve('./preset_3'), +]); +``` + +### hasPlugins +判断是否有注册某个插件,插件的 id 规则: +- id 默认为包名 +- 内置插件以 `@@` 为前缀,比如 `@@/registerMethod` + +用法:**hasPlugins(pluginIds: string[])** + +例如 +```js +// 判断是否有注册 @fesjs/plugin-locale +api.hasPlugins(['@fesjs/plugin-locale']); +``` + +::: tip +如果在注册阶段使用,只能判断在他之前是否有注册某个插件。 +::: + +### hasPresets +判断是否有注册某个插件集。 + +用法:**hasPresets(presetIds: string[])** + +例如 +```js +// 判断是否有注册 +api.hasPlugins(['@fesjs/preset-xxx']); +``` + +::: tip +如果在注册阶段使用,只能判断在他之前是否有注册某个插件集。 +::: + +## 扩展方法 + +通过 api.registerMethod() 扩展的方法。 + +### onStart +在命令注册函数执行前触发。可以使用 config 和 paths。 + +### onExit +dev 退出时触发。 + +### onGenerateFiles +生成临时文件,触发时机在 webpack 编译之前。 + +### addPluginExports +把插件需要导出的运行时 API 写入`@fesjs/fes`。 +```js +api.addPluginExports(() => [ + { + specifiers: ['access', 'useAccess'], + source: absoluteFilePath + } +]); +``` +这样用户使用时: +```js +import { access, useAccess } from '@fesjs/fes'; +``` + +### addRuntimePlugin +添加运行时插件,返回值格式为表示文件路径的字符串。Fes.js 会把 + +例如: +```js +api.addRuntimePlugin(() => join(__dirname, './runtime')); +``` + +### addRuntimePluginKey +添加运行时插件的 key,返回值格式为字符串。 + +例如: +```js +api.addRuntimePluginKey(() => 'some'); +``` + +### addEntryImportsAhead +在入口文件现有 import 的前面添加 import。 + +例如: +```js +api.addEntryImportsAhead(() => [{ source: 'anypackage' }]); +``` + +### addEntryImports +在入口文件现有 import 的后面添加 import。 + +例如: +```js +api.addEntryImport(() => { + return [ + { + source: '/modulePath/xxx.js', + specifier: 'moduleName', + } + ] +}); +``` + +### addEntryCodeAhead +在入口文件最前面(import 之后)添加代码。 + +例如: +```js +api.addEntryCodeAhead( + () => `${globalCSSFile + .map(file => `require('${winPath(relative(absTmpPath, file))}');`) + .join('')}` + +``` + +### addEntryCode +在入口文件最后添加代码。 + +例如: +```js +api.addEntryCode(() => { + return `console.log('works!')` +}) +``` + +### addBeforeMiddlewares +添加在 `webpack compiler` 中间件之前的中间件,返回值格式为 `express` 中间件。 + +例如: +```js +api.addBeforeMiddlewares(() => { + return (req, res, next) => { + if (false) { + res.end('end'); + } else { + next(); + } + }; +}); +``` + +### addMiddlewares +添加在 `webpack compiler` 中间件之后的中间件,返回值格式为 `express` 中间件。 + +### modifyRoutes + +修改路由。 + +例如: +```js +// 把BaseLayout插入到路由配置中,作为根路由 +api.modifyRoutes(routes => [ + { + path: '/', + component: winPath( + join(api.paths.absTmpPath || '', absFilePath) + ), + children: routes + } +]); +``` + +### modifyBundleConfigOpts +修改获取 bundleConfig 的函数参数。 + +例如: +```js +api.modifyBundleConfigOpts(memo => { + memo.miniCSSExtractPluginPath = require.resolve('mini-css-extract-plugin'); + memo.miniCSSExtractPluginLoaderPath = require.resolve( + 'mini-css-extract-plugin/dist/loader', + ); + return memo; +}); + +``` + +### modifyBundleConfig +修改 bundle 配置。 + +```js +api.modifyBundleConfig((bundleConfig) => { + // do something + return bundleConfig; +}); +``` + +### modifyBabelOpts +修改 babel 配置项。 + +例如: +```js +api.modifyBabelOpts((babelOpts) => { + if (api.config.babelPluginImport) { + api.config.babelPluginImport.forEach((config) => { + babelOpts.plugins.push(['import', config]); + }); + } + return babelOpts; +}); +``` + +### modifyBabelPresetOpts +修改 babel 插件的配置。 + +例如: +```js +api.modifyBabelPresetOpts(opts => { + return { + ...opts, + import: (opts.import || []).concat([ + { libraryName: 'ant-design-vue', libraryDirectory: 'es', style: true }, + ]), + }; +}); +``` + +### modifyPaths +修改 paths 对象。 + + +### modifyConfig +修改最终配置。 + +例如: +```js +api.modifyConfig((memo) => { + return { + ...memo, + ...defaultOptions, + }; +}); + +``` + +### chainWebpack +通过 [webpack-chain] 的方式修改 webpack 配置。 + +例如: +```js +api.chainWebpack((memo) => { + memo.resolve.alias.set('vue-i18n', 'vue-i18n/dist/vue-i18n.esm-bundler.js'); +}); +``` + +### addTmpGenerateWatcherPaths +添加重新临时文件生成的监听路径。 + +例如: +```js +api.addTmpGenerateWatcherPaths(() => [ + './app.js', +]); +``` + +### writeTmpFile +写临时文件。 + +例如: +```js +api.writeTmpFile({ + path: absoluteFilePath, + content: Mustache.render( + readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'), + { + REPLACE_ROLES: JSON.stringify(roles) + } + ) +}); +``` + +参数: + +- path:相对于临时文件夹的路径 +- content:文件内容 + +::: tip +不能在注册阶段使用,通常放在 api.onGenerateFiles() 里,这样能在需要时重新生成临时文件 +临时文件的写入做了缓存处理,如果内容一致,不会做写的操作,以减少触发 webpack 的重新编译 +::: + +### copyTmpFiles +批量写临时文件。 + +例如: +```js + api.copyTmpFiles({ + namespace, + path: join(__dirname, 'runtime'), + ignore: ['.tpl'] +}); +``` + +参数: + +- namespace:复制到临时文件夹下的目标目录 +- path:需要复制的文件目录 +- ignore:需要排除的文件 + +::: tip +不能在注册阶段使用,通常放在 api.onGenerateFiles() 里,这样能在需要时重新生成临时文件 +临时文件的写入做了缓存处理,如果内容一致,不会做写的操作,以减少触发 `webpack` 的重新编译 +::: \ No newline at end of file diff --git a/packages/fes-template/.env b/packages/fes-template/.env index 84b044a1..24f1c637 100644 --- a/packages/fes-template/.env +++ b/packages/fes-template/.env @@ -1,2 +1 @@ -FES_APP_PUBLISH_ERROR_PAGE=hello -ANALYZE=1 +FES_APP_PUBLISH_ERROR_PAGE=hello \ No newline at end of file