"use strict";(self.webpackChunkfes_js=self.webpackChunkfes_js||[]).push([[287],{4020:(n,s,a)=>{a.r(s),a.d(s,{data:()=>p});const p={key:"v-c5618810",path:"/reference/plugin/dev/api.html",title:"插件 API",lang:"zh-CN",frontmatter:{},excerpt:"",headers:[{level:2,title:"属性",slug:"属性",children:[{level:3,title:"api.paths",slug:"api-paths",children:[]},{level:3,title:"api.cwd",slug:"api-cwd",children:[]},{level:3,title:"api.pkg",slug:"api-pkg",children:[]},{level:3,title:"api.configInstance",slug:"api-configinstance",children:[]},{level:3,title:"userConfig",slug:"userconfig",children:[]},{level:3,title:"config",slug:"config",children:[]},{level:3,title:"env",slug:"env",children:[]},{level:3,title:"args",slug:"args",children:[]}]},{level:2,title:"核心方法",slug:"核心方法",children:[{level:3,title:"describe",slug:"describe",children:[]},{level:3,title:"register",slug:"register",children:[]},{level:3,title:"applyPlugins",slug:"applyplugins",children:[]},{level:3,title:"registerMethod",slug:"registermethod",children:[]},{level:3,title:"registerCommand",slug:"registercommand",children:[]},{level:3,title:"registerPresets",slug:"registerpresets",children:[]},{level:3,title:"registerPlugins",slug:"registerplugins",children:[]},{level:3,title:"hasPlugins",slug:"hasplugins",children:[]},{level:3,title:"hasPresets",slug:"haspresets",children:[]},{level:3,title:"skipPlugins",slug:"skipplugins",children:[]}]},{level:2,title:"扩展方法",slug:"扩展方法",children:[{level:3,title:"addPluginExports",slug:"addpluginexports",children:[]},{level:3,title:"addCoreExports",slug:"addcoreexports",children:[]},{level:3,title:"addRuntimePlugin",slug:"addruntimeplugin",children:[]},{level:3,title:"addRuntimePluginKey",slug:"addruntimepluginkey",children:[]},{level:3,title:"addEntryImportsAhead",slug:"addentryimportsahead",children:[]},{level:3,title:"addEntryImports",slug:"addentryimports",children:[]},{level:3,title:"addEntryCodeAhead",slug:"addentrycodeahead",children:[]},{level:3,title:"addEntryCode",slug:"addentrycode",children:[]},{level:3,title:"addHTMLHeadScripts",slug:"addhtmlheadscripts",children:[]},{level:3,title:"addBeforeMiddlewares",slug:"addbeforemiddlewares",children:[]},{level:3,title:"addMiddlewares",slug:"addmiddlewares",children:[]},{level:3,title:"addTmpGenerateWatcherPaths",slug:"addtmpgeneratewatcherpaths",children:[]},{level:3,title:"chainWebpack",slug:"chainwebpack",children:[]},{level:3,title:"copyTmpFiles",slug:"copytmpfiles",children:[]},{level:3,title:"getPort",slug:"getport",children:[]},{level:3,title:"getHostname",slug:"gethostname",children:[]},{level:3,title:"getServer",slug:"getserver",children:[]},{level:3,title:"getRoutes",slug:"getroutes",children:[]},{level:3,title:"getRoutesJSON",slug:"getroutesjson",children:[]},{level:3,title:"modifyRoutes",slug:"modifyroutes",children:[]},{level:3,title:"modifyBundleConfigOpts",slug:"modifybundleconfigopts",children:[]},{level:3,title:"modifyBundleConfig",slug:"modifybundleconfig",children:[]},{level:3,title:"modifyBabelOpts",slug:"modifybabelopts",children:[]},{level:3,title:"modifyBabelPresetOpts",slug:"modifybabelpresetopts",children:[]},{level:3,title:"modifyPaths",slug:"modifypaths",children:[]},{level:3,title:"modifyDefaultConfig",slug:"modifydefaultconfig",children:[]},{level:3,title:"modifyConfig",slug:"modifyconfig",children:[]},{level:3,title:"modifyPublicPathStr",slug:"modifypublicpathstr",children:[]},{level:3,title:"onPluginReady",slug:"onpluginready",children:[]},{level:3,title:"onStart",slug:"onstart",children:[]},{level:3,title:"onExit",slug:"onexit",children:[]},{level:3,title:"onGenerateFiles",slug:"ongeneratefiles",children:[]},{level:3,title:"restartServer",slug:"restartserver",children:[]},{level:3,title:"writeTmpFile",slug:"writetmpfile",children:[]}]}],filePathRelative:"reference/plugin/dev/api.md",git:{updatedTime:1653450562e3,contributors:[{name:"wanchun",email:"445436867@qq.com",commits:1}]}}},7965:(n,s,a)=>{a.r(s),a.d(s,{default:()=>T});var p=a(6252);const e=(0,p.uE)('
一些关键的路径:
build
产物的绝对路径src
目录的绝对路径pages
目录的绝对路径.fes
临时文件目录的绝对路径执行命令的绝对路径
package.json
的内容
config
实例
用户配置
插件配置可被修改,此为最终的配置
process.env
环境变量
注册阶段执行,用于描述插件或插件集的 id、key、配置信息、启用方式等。
用法:describe({ id?: string, key?: string, config?: { default, schema, onChange } }, enableBy?)
例如:
api.describe({\n key: 'esbuild',\n config: {\n schema(joi) {\n return joi.object();\n },\n default: {}\n },\n enableBy: api.EnableBy.config,\n});\n
注:
',26),t=(0,p._)("li",null,[(0,p._)("code",null,"config.default"),(0,p.Uk)(" 为配置的默认值,用户没有配置时取这个")],-1),o=(0,p._)("code",null,"config.schema",-1),c=(0,p.Uk)(" 用于声明配置的类型,基于 "),l={href:"https://hapi.dev/module/joi",target:"_blank",rel:"noopener noreferrer"},i=(0,p.Uk)("joi"),r=(0,p.Uk)(",如果你希望用户进行配置,这个是必须的,否则用户的配置无效"),u=(0,p._)("li",null,[(0,p._)("code",null,"config.onChange"),(0,p.Uk)(" 是 "),(0,p._)("code",null,"dev"),(0,p.Uk)(" 阶段配置被修改后的处理机制,默认会重启 dev 进程,也可以修改为 api.ConfigChangeType.regenerateTmpFiles 只重新生成临时文件,还可以通过函数的格式自定义")],-1),d=(0,p._)("li",null,[(0,p._)("code",null,"enableBy"),(0,p.Uk)(" 为启用方式,默认是注册启用,可更改为 "),(0,p._)("code",null,"api.EnableBy.config"),(0,p.Uk)(",还可以用自定义函数的方式决定其启用时机(动态生效)")],-1),k=(0,p.uE)('为 api.applyPlugins 注册可供其使用的 hook。
用法:register({ key: string, fn: Function, pluginId?: string, before?: string, stage?: number })
参数:
api.applyPlugins
时,此函数被执行。// 可同步\napi.register({\n key: 'foo',\n fn() {\n return 'a';\n },\n});\n\n// 可异步\napi.register({\n key: 'foo',\n async fn() {\n await delay(100);\n return 'b';\n },\n});\n
注意:
api.appyPlugins
的 type
参数来看,如果是 api.ApplyPluginsType.add
,需有返回值,这些返回值最终会被合成一个数组。如果是 api.ApplyPluginsType.modify
,需对第一个参数做修改,并返回它,它会作为下个hook的参数。 如果是 api.ApplyPluginsType.event
,无需返回值取得 register 注册的 hooks 执行后的数据。
用法:applyPlugins({ key: string, type: api.ApplyPluginsType, initialValue?: any, args?: any })
参数:
例如:
const foo = await api.applyPlugins({\n key: 'foo',\n type: api.ApplyPluginsType.add,\n initialValue: [],\n});\nconsole.log(foo); // ['a', 'b']\n
编译时插件hook执行类型,enum 类型,包含三个属性:
往 api
上注册方法。如果有提供 fn
,则执行 fn
定义的函数。
用法:registerMethod({ name: string, fn?: Function, exitsError?: boolean })
例如:
api.registerMethod({\n name: 'writeTmpFile',\n fn({\n path,\n content\n }) {\n assert(\n api.stage >= api.ServiceStage.pluginReady,\n 'api.writeTmpFile() should not execute in register stage.'\n );\n const absPath = join(api.paths.absTmpPath, path);\n api.utils.mkdirp.sync(dirname(absPath));\n if (!existsSync(absPath) || readFileSync(absPath, 'utf-8') !== content) {\n writeFileSync(absPath, content, 'utf-8');\n }\n }\n});\n
然后在插件中可以使用:
api.writeTmpFile()\n
例如:
api.registerCommand({\n command: 'webpack',\n description: 'inspect webpack configurations',\n options: [{\n name: '--rule <ruleName>',\n description: 'inspect a specific module rule'\n }, {\n name: '--plugin <pluginName>',\n description: 'inspect a specific plugin'\n }, {\n name: '--rules',\n description: 'list all module rule names'\n }, {\n name: '--plugins',\n description: 'list all plugin names'\n }, {\n name: '--verbose',\n description: 'show full function definitions in output'\n }],\n async fn({ rawArgv, args, options, program}) {\n }\n})\n
当项目引入此插件后,使用:
fes webpack\n
注册插件集,参数为路径数组。
用法:registerPresets(presets: string[])
例如:
api.registerPresets([\n { id: 'preset_2', key: 'preset2', apply: () => () => {} },\n require.resolve('./preset_3'),\n]);\n
注册插件,参数为路径数组。
用法:registerPlugins(plugins: string[])
例如:
api.registerPlugins([\n { id: 'preset_2', key: 'preset2', apply: () => () => {} },\n require.resolve('./preset_3'),\n]);\n
判断是否有注册某个插件,插件的 id 规则:
@@
为前缀,比如 @@/registerMethod
用法:hasPlugins(pluginIds: string[])
例如
// 判断是否有注册 @fesjs/plugin-locale\napi.hasPlugins(['@fesjs/plugin-locale']);\n
提示
如果在注册阶段使用,只能判断在他之前是否有注册某个插件。
判断是否有注册某个插件集。
用法:hasPresets(presetIds: string[])
例如
// 判断是否有注册\napi.hasPlugins(['@fesjs/preset-xxx']);\n
提示
如果在注册阶段使用,只能判断在他之前是否有注册某个插件集。
声明哪些插件需要被禁用,参数为插件 id 的数组。
用法:hasPresets(presetIds: string[])
例如:
// 禁用 plugin-model 插件\napi.skipPlugins(['@fesjs/plugin-model']);\n
通过 api.registerMethod() 扩展的方法。
把插件需要导出的运行时 API 写入@fesjs/fes
。
api.addPluginExports(() => [\n {\n specifiers: ['access', 'useAccess'],\n source: absoluteFilePath\n }\n]);\n
这样用户使用时:
import { access, useAccess } from '@fesjs/fes';\n
提供给其他插件运行时需要的 API。
api.addCoreExports(() => [\n {\n specifiers: ['getRoutes', 'getRouter', 'getHistory', 'destroyRouter'],\n source: absCoreFilePath\n }\n]);\n
使用:
import { getHistory, destroyRouter } from '@@/core/coreExports';\n
添加运行时插件,返回值格式为表示文件路径的字符串。
例如:
api.addRuntimePlugin(() => join(__dirname, './runtime'));\n
添加插件提供的运行时配置的 key,返回值格式为字符串。
例如:
api.addRuntimePluginKey(() => 'some');\n
则用户可以:
// app.js\nconst some = function(){\n return {\n\n }\n}\n\n
在入口文件现有 import 的前面添加 import。
例如:
api.addEntryImportsAhead(() => [{ source: 'anypackage' }]);\n
在入口文件现有 import 的后面添加 import。
例如:
api.addEntryImport(() => {\n return [\n {\n source: '/modulePath/xxx.js',\n specifier: 'moduleName',\n }\n ]\n});\n
在入口文件最前面(import 之后)添加代码。
例如:
api.addEntryCodeAhead(\n () => `${globalCSSFile\n .map(file => `require('${winPath(relative(absTmpPath, file))}');`)\n .join('')}`\n\n
在入口文件最后添加代码。
例如:
api.addEntryCode(() => {\n return `console.log('works!')`\n})\n
在 HTML 头部添加脚本。
例如:
api.addHTMLHeadScripts(() => {\n return [\n {\n content: '',\n src: '',\n // ...attrs\n },\n ];\n});\n
添加在 webpack compiler
中间件之前的中间件,返回值格式为 express
中间件。
例如:
api.addBeforeMiddlewares(() => {\n return (req, res, next) => {\n if (false) {\n res.end('end');\n } else {\n next();\n }\n };\n});\n
添加在 webpack compiler
中间件之后的中间件,返回值格式为 express
中间件。
添加重新生成临时文件的监听路径。
例如:
api.addTmpGenerateWatcherPaths(() => [\n './app.js',\n]);\n
通过 [webpack-chain] 的方式修改 webpack 配置。
例如:
api.chainWebpack((memo) => {\n memo.resolve.alias.set('vue-i18n', 'vue-i18n/dist/vue-i18n.esm-bundler.js');\n});\n
批量写临时文件。
例如:
api.copyTmpFiles({\n namespace,\n path: join(__dirname, 'runtime'),\n ignore: ['.tpl']\n});\n
参数:
提示
不能在注册阶段使用,通常放在 api.onGenerateFiles() 里,这样能在需要时重新生成临时文件 临时文件的写入做了缓存处理,如果内容一致,不会做写的操作,以减少触发 webpack
的重新编译
获取端口号,dev 时有效。
获取 hostname,dev 时有效。
获取 devServer,dev 时有效。
获取 api.modifyRoutes
修改过后的路由信息。
获取格式化后的路由信息
修改路由。
例如:
// 把BaseLayout插入到路由配置中,作为根路由\napi.modifyRoutes(routes => [\n {\n path: '/',\n component: winPath(\n join(api.paths.absTmpPath || '', absFilePath)\n ),\n children: routes\n }\n]);\n
修改获取 bundleConfig 的函数参数。
例如:
api.modifyBundleConfigOpts(memo => {\n memo.miniCSSExtractPluginPath = require.resolve('mini-css-extract-plugin');\n memo.miniCSSExtractPluginLoaderPath = require.resolve(\n 'mini-css-extract-plugin/dist/loader',\n );\n return memo;\n});\n\n
修改 bundle 配置。
api.modifyBundleConfig((bundleConfig) => {\n // do something\n return bundleConfig;\n});\n
修改 babel 配置项。
例如:
api.modifyBabelOpts((babelOpts) => {\n if (api.config.babelPluginImport) {\n api.config.babelPluginImport.forEach((config) => {\n babelOpts.plugins.push(['import', config]);\n });\n }\n return babelOpts;\n});\n
修改 babel 插件的配置。
例如:
api.modifyBabelPresetOpts(opts => {\n return {\n ...opts,\n import: (opts.import || []).concat([\n { libraryName: 'ant-design-vue', libraryDirectory: 'es', style: true },\n ]),\n };\n});\n
修改 paths 对象。
修改默认配置。 例如:
api.modifyDefaultConfig((memo) => {\n return {\n ...memo,\n ...defaultOptions,\n };\n});\n
修改最终配置。
例如:
api.modifyConfig((memo) => {\n return {\n ...memo,\n ...defaultOptions,\n };\n});\n\n
修改 publicPath 字符串。
例如:
api.modifyPublicPathStr(() => {\n return api.config.publicPath || '/';\n});\n
在插件初始化完成触发。在 onStart 之前,此时还没有 config 和 paths,他们尚未解析好。
在命令注册函数执行前触发。可以使用 config 和 paths。
dev 退出时触发。
生成临时文件,触发时机在 webpack 编译之前。
重启 devServer,dev 时有效。
写临时文件。
例如:
api.writeTmpFile({\n path: absoluteFilePath,\n content: Mustache.render(\n readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'),\n {\n REPLACE_ROLES: JSON.stringify(roles)\n }\n )\n});\n
参数:
提示
不能在注册阶段使用,通常放在 api.onGenerateFiles() 里,这样能在需要时重新生成临时文件 临时文件的写入做了缓存处理,如果内容一致,不会做写的操作,以减少触发 webpack 的重新编译