取得 register 注册的 hooks 执行后的数据。
e.g.
const foo = await api.applyPlugins({key: 'foo',type: api.ApplyPluginsType.add,initialValue: [],});console.log(foo); // ['a', 'b']
注册阶段执行,用于描述插件或插件集的 id、key、配置信息、启用方式等。
e.g.
api.describe({key: 'history',config: {default: 'browser',schema(joi) {return joi.string();},onChange: api.ConfigChangeType.regenerateTmpFiles,},enableBy: api.EnableBy.config,});
注:
config.default
为配置的默认值,用户没有配置时取这个config.schema
用于声明配置的类型,基于 joi,如果你希望用户进行配置,这个是必须的,否则用户的配置无效config.onChange
是 dev 阶段配置被修改后的处理机制,默认会重启 dev 进程,也可以修改为 api.ConfigChangeType.regenerateTmpFiles
只重新生成临时文件,还可以通过函数的格式自定义enableBy
为启用方式,默认是注册启用,可更改为 api.EnableBy.config
,还可以用自定义函数的方式决定其启用时机(动态生效)为 api.applyPlugins
注册可供其使用的 hook。
e.g.
// 可同步api.register({key: 'foo',fn() {return 'a';},});// 可异步api.register({key: 'foo',async fn() {await delay(100);return 'b';},});
然后通过 api.applyPlugins
即可拿到 ['a', 'b']
,
const foo = await api.applyPlugins({key: 'foo',type: api.ApplyPluginsType.add,initialValue: [],});console.log(foo); // ['a', 'b']
注:
api.appyPlugins
的 type 参数来看 _ 如果是 api.ApplyPluginsType.add
,需有返回值,这些返回值最终会被合成一个数组 _ 如果是 api.ApplyPluginsType.modify
,需对第一个参数做修改,并返回 * 如果是 api.ApplyPluginsType.event
,无需返回值注册命令。
e.g.
api.registerCommand({name: 'generate',alias: 'g',fn: async ({ args }) => {await delay(100);return `hello ${api.args.projectName}`;},});
注:
alias
为别名,比如 generate 的别名 gfn
的参数为 { args }
,args 的格式同 yargs 的解析结果,需要注意的是 _
里的 command 本身被去掉了,比如执行 umi generate page foo
,args._
为 ['page', 'foo']
往 api 上注册方法。可以是 api.register()
的快捷使用方式,便于调用;也可以不是,如果有提供 fn
,则执行 fn
定义的函数。
e.g.
api.registerMethod({name: 'foo',fn() { return 'foo'; },exitsError: false,});
注:
api.register()
就好exitsError
默认为 true,如果方法存在则报错注册插件集,参数为路径数组。
e.g.
api.registerPresets([{ id: 'preset_2', key: 'preset2', apply: () => () => {} },require.resolve('./preset_3'),]);
注册插件,参数为路径数组。
e.g.
api.registerPlugins([{ id: 'preset_2', key: 'preset2', apply: () => () => {} },require.resolve('./preset_3'),]);
判断是否有注册某个插件。
插件的 id 规则,
@umijs/preset-react/lib/plugins/crossorigin/crossorigin
@@
为前缀,比如 @@/registerMethod
注:
e.g.
// 判断是否有注册 @umijs/plugin-dvaapi.hasPlugins(['@umijs/plugin-dva']);
判断是否有注册某个插件集。
插件集的 id 规则,
e.g.
// 判断是否有注册 @umijs/preset-uiapi.hasPresets(['@umijs/preset-ui']);
注:
声明哪些插件需要被禁用,参数为插件 id 的数组。
e.g.
// 禁用 plugin-dva 插件api.skipPlugins(['@umijs/plugin-dva']);
通过 api.registerMethod()
扩展的方法。
添加在 webpack compiler 中间件之前的中间件,返回值格式为 express 中间件。
e.g.
api.addBeforeMiddlewares(() => {return (req, res, next) => {if (false) {res.end('end');} else {next();}};});
添加依赖信息,包括 semver range 和别名信息。
api.addDepInfo((memo) => {return {name: 'foo',range: pkg.dependencies.foo,alias: [pathToFooPackage],};});
在入口文件最后添加代码。
e.g.
api.addEntryCode(() => {return `console.log('works!')`})
在入口文件最前面(import 之后)添加代码。
e.g.
api.addEntryCodeAhead(() => {return `console.log('works!')`})
在入口文件现有 import 的后面添加 import。
e.g.
api.addEntryImport(() => {return [{source: '/modulePath/xxx.js',specifier: 'moduleName',}]});
在入口文件现有 import 的前面添加 import。
e.g.
api.addEntryImportsAhead(() => [{ source: 'anypackage' }]);
在 HTML 中添加 meta 标签。
e.g.
api.addHTMLMetas(() => {return [{name: 'keywords',content: 'umi, umijs'},];});
在 HTML 中添加 Link 标签。
e.g.
api.addHTMLLinks(() => {return [{rel: 'shortcut icon',type: 'image/x-icon',href: api.config.favicon!,},];});
在 HTML 中添加 Style 标签。
e.g.
api.addHTMLStyles(() => {return [{content:`.className { }`}];});
在 HTML 尾部添加脚本。
e.g.
api.addHTMLScripts(() => {return [{content: '',src: '',// ...attrs},];});
在 HTML 头部添加脚本。
e.g.
api.addHTMLHeadScripts(() => {return [{content: '',src: '',// ...attrs},];});
添加在 webpack compiler 中间件之后的中间件,返回值格式为 express 中间件。
e.g.
api.addMiddlewares(async (ctx: Context, next: any) => {// do something before requestawait next();// do something after request});
添加补充相关的 import,在整个应用的最前面执行。
e.g.
api.addPolyfillImports(() => [{ source: './core/polyfill' }]);
添加以项目依赖为优先的依赖库列表,返回值为 { name: string; path: string }
。
e.g.
api.addProjectFirstLibraries(() => ({name: 'antd',path: dirname(require.resolve('antd/package.json')),}));
比如:
api.addProjectFirstLibraries(() => ({ name: 'antd', path: dirname(require.resolve('antd/package.json')) }))
,然后用户依赖 antd 时,如果项目有依赖 antd,会用项目依赖的 antd,否则用内置的 antd添加运行时插件,返回值格式为表示文件路径的字符串。
e.g.
api.addRuntimePlugin(() => join(__dirname, './runtime'));
添加运行时插件的 key,返回值格式为字符串。
e.g.
api.addRuntimePluginKey(() => 'some');
内置的初始值有:
添加需要 umi 额外导出的内容,返回值格式为 { source: string, specifiers?: (string | { local: string, exported: string })[], exportAll?: boolean }
。
比如 api.addUmiExports(() => { source: 'dva', specifiers: ['connect'] })
,然后就可以通过 import { connect } from 'umi'
使用 dva
的 connect
方法了。
添加重新临时文件生成的监听路径。
e.g.
api.addTmpGenerateWatcherPaths(() => ['./app.ts',]);
通过 webpack-chain 的方式修改 webpack 配置。
比如:
api.chainWebpack((config, { webpack, env, createCSSRule }) => {// Set aliasconfig.resolve.alias.set('a', 'path/to/a');// Delete progress bar pluginconfig.plugins.delete('progress');return config;});
注:
获取端口号,dev 时有效。
e.g.
const Port = api.getPort()
获取 hostname,dev 时有效。
e.g.
const hostname = api.getHostname()
修改 babel 配置项。
e.g.
api.modifyBabelOpts(babelOpts => {const hmr = api.config.dva?.hmr;if (hmr) {const hmrOpts = lodash.isPlainObject(hmr) ? hmr : {};babelOpts.plugins.push([require.resolve('babel-plugin-dva-hmr'),hmrOpts,]);}return babelOpts;});
修改 @umijs/babel-preset-umi 的配置项。
e.g.
api.modifyBabelPresetOpts(opts => {return {...opts,import: (opts.import || []).concat([{ libraryName: 'antd', libraryDirectory: 'es', style: true },{ libraryName: 'antd-mobile', libraryDirectory: 'es', style: true },]),};});
修改 bundle 配置。
e.g.
api.modifyBundleConfig((bundleConfig, { env, type, bundler: { id } }) => {// do somethingreturn bundleConfig;});
参数:
initialValue
:bundleConfig,可能是 webpack 的配置,通过 bundler.id
区分args
_ type
:现在有两个,ssr 和 csr _ env
:即 api.env * bundler
:包含 id 和 version,比如:{ id: 'webpack': version: 4 }
修改 bundle 配置数组,比如可用于 dll、modern mode 的处理。
e.g.
api.modifyBundleConfigs(async (memo, { getConfig }) => {return [...memo];});
参数:
args
_ getConfig()
:用于获取额外的一份配置 _ env
:即 api.env * bundler
:包含 id 和 version,比如:{ id: 'webpack': version: 4 }
修改获取 bundleConfig 的函数参数。
e.g.
api.modifyBundleConfigOpts(memo => {memo.miniCSSExtractPluginPath = require.resolve('mini-css-extract-plugin');memo.miniCSSExtractPluginLoaderPath = require.resolve('mini-css-extract-plugin/dist/loader',);return memo;});
比如用于切换到 webpack@5 或其他。
e.g.
import webpack from 'webpack';// 换成 webpack@5api.modifyBundleImplementor(() => {return webpack;});
比如用于切换到 parcel 或 rollup 做构建。
e.g.
api.modifyBundler(() => {return require('@umijs/bundler-rollup').Bundler;});
修改最终配置。
e.g.
api.modifyConfig((memo) => {return {...memo,...defaultOptions,};});
注:
修改默认配置。
e.g.
api.modifyDefaultConfig((memo) => {return {...memo,...defaultOptions,};});
修改 HTML,基于 cheerio 的 ast。
e.g.
api.modifyHTML(($, { route }) => {$('h2').addClass('welcome');return $;});
修改 html 中的js文件引入,可以用于不同的页面使用,不同的 chunks 配置。
e.g.
api.modifyHTMLChunks(async (memo, opts) => {const { route } = opts;// do somethingreturn memo;});
修改导出路由对象 routeMap
(路由与输出 HTML 的映射关系),触发时机在 HTML 文件生成之前,默认值为 [{ route: { path: '/' }, file: 'index.html' }]
。
参数:
html
:HTML 工具类实例注:
umi build
时起效例如 exportStatic
插件根据路由生成对应 HTML:
api.modifyExportRouteMap(async (defaultRouteMap, { html }) => {return await html.getRouteMap();});
umi dev
时修改输出的 HTML 内容。
参数:
req
:Request 对象,可获取当前访问路径例如希望 /404
路由直接返回 Not Found
:
api.modifyDevHTMLContent(async (defaultHtml, { req }) => {if (req.path === '/404') {return 'Not Found';}return defaultHtml;})
umi build
时修改输出的 HTML 内容。
参数(相当于一个 RouteMap
对象):
route
:路由对象file
:输出 HTML 名称例如可以在生成 HTML 文件前,做预渲染:
api.modifyProdHTMLContent(async (content, args) => {const { route } = args;const render = require('your-renderer');return await render({path: route.path,})});
修改 paths 对象。
e.g.
api.modifyPaths(async (paths) => {return memo;});
参数:
initialValue
: paths 对象修改 renderer 路径,用于使用自定义的 renderer。
e.g.
api.modifyRendererPath(() => {return dirname(require.resolve('@umijs/renderer-mpa/package.json'));});
修改 publicPath 字符串。
e.g.
api.modifyPublicPathStr(() => {return api.config.publicPath || '/';});
参数:
route
: 当前路由注:
修改路由。
e.g.
api.modifyRoutes((routes: any[]) => {return resetMainPath(routes, api.config.mainPath);});
修改路由项。
e.g.
api.onPatchRoute(({ route }) => {if (!api.config.exportStatic?.htmlSuffix) return;if (route.path) {route.path = addHtmlSuffix(route.path, !!route.routes);}});
修改路由项。
e.g.
api.onPatchRouteBefore(({ route }) => {if (!api.config.exportStatic?.htmlSuffix) return;if (route.path) {route.path = addHtmlSuffix(route.path, !!route.routes);}});
修改路由数组。
e.g.
api.onPatchRoutes(({ routes }) => {// copy / to /index.htmllet rootIndex = null;routes.forEach((route, index) => {if (route.path === '/' && route.exact) {rootIndex = index;}});if (rootIndex !== null) {routes.splice(rootIndex, 0, {...routes[rootIndex],path: '/index.html',});}});
修改路由数组。
e.g.
api.onPatchRoutesBefore(({ routes }) => {// copy / to /index.htmllet rootIndex = null;routes.forEach((route, index) => {if (route.path === '/' && route.exact) {rootIndex = index;}});if (rootIndex !== null) {routes.splice(rootIndex, 0, {...routes[rootIndex],path: '/index.html',});}});
构建完成时可以做的事。
e.g.
api.onBuildComplete(({ err }) => {if (!err) {// do something}});
注:
编译完成时可以做的事。
e.g.
api.onDevCompileDone(({ stats, type }) => {// don't need ssr bundler chunksif (type === BundlerConfigType.ssr) {return;}// store client build chunkssharedMap.set('chunks', stats.compilation.chunks);});
注:
生成临时文件,触发时机在 webpack 编译之前。
e.g.
api.onGenerateFiles(() => {api.writeTmpFile({path: 'any.ts',content: '',});});
在插件初始化完成触发。在 onStart
之前,此时还没有 config 和 paths,他们尚未解析好。
e.g.
api.onPluginReady(() => {// do something});
在命令注册函数执行前触发。可以使用 config 和 paths。
e.g.
api.onStart(() => {// do something});
dev 退出时触发。
e.g.
api.onExit(() => {// do something});
参数:
signal
: 值为 SIGINT、SIGQUIT 或 SIGTERM注:
写临时文件。
e.g.
api.onGenerateFiles(() => {api.writeTmpFile({path: 'any.ts',content: '',});});
参数:
path
:相对于临时文件夹的路径content
:文件内容skipTSCheck
:默认为 true
,path
为 ts 或 tsx 文件,不检查 TypeScript 类型错误,如果希望插件对用户项目进行 TypeScript 类型检查,可以设置为 false
。注:
api.onGenerateFiles()
里,这样能在需要时重新生成临时文件命令行参数。
设置需要走 babel 编译的文件列表。
注:
用户配置。
注:
const { config } = api;
然后在函数体里使用,而是需要在里面通过 api.paths.cwd
使用当前路径。
即 process.env.NODE_ENV,可能有 development
、production
和 test
。
比如,
umi dev --foo
,args 为 { _: [], foo: true }
umi g page index --typescript --less
,args 为 { _: ['page', 'index'], typescript: true, less: true }
插件 id,通常是包名。
插件日志类,包含 api.logger.(log|info|debug|error|warn|profile)
其中 api.logger.profile
可用于性能耗时记录,例如:
export default api => {api.logger.profile('barId');setTimeout(() => {api.logger.profile('barId');});};// => [PROFILE] Completed in *ms
插件的配置 key,通常是包名的简写。
比如 @umijs/plugin-dva
,其 key 为 dva
;比如 umi-plugin-antd
,其 key 为 antd
。
相关路径,包含:
cwd
,当前路径absSrcPath
,src 目录绝对路径,需注意 src 目录是可选的,如果没有 src 目录,absSrcPath
等同于 cwd
absPagesPath
,pages 目录绝对路径absTmpPath
,临时目录绝对路径absOutputPath
,输出路径,默认是 ./dist
absNodeModulesPath
,node_modules 目录绝对路径aliasedTmpPath
,以 @
开头的临时路径,通常用于注:
const { paths } = api;
然后在函数体里 paths.cwd
使用,而是需要在里面通过 api.paths.cwd
使用当前项目的 package.json,格式为 Object。
Service 实例。通常不需要用到,除非你知道为啥要用。
Service 运行阶段。
纯用户配置,就是 .umirc
或 config/config
里的内容,没有经过 defaultConfig 以及插件的任何处理。
注:
utils 方法,详见 @umijs/utils/src/index.ts。 包含外部库:
lodash
: 导出自 lodash
, 实用的 js 工具库。got
: 导出自 got
, 轻量级的请求库。deepmerge
: 导出自 deepmerge
, 将两个对象的可以枚举属性深度合并。semver
: 导出自 semver
, 用于实现版本号的解析和比较,规范版本号的格式。常见于版本过低提示用户升级等场景。Mustache
: 导出自 mustache
, 无逻辑的模版语法,是 JavaScript 中的 mustache 模板系统的零依赖实现。address
: 导出自 address
, 用于获取当前计算机的 IP ,MAC 和 DNS 服务器地址等。cheerio
: 导出自 cheerio
, 用于方便的处理爬取到的网页内容,在服务端对 DOM 结构进行方便的操作。clipboardy
: 导出自 clipboardy
, 用于对剪贴板内容写入与读取的处理。chokidar
: 导出自 chokidar
, 用于监听文件的变化。createDebug
, Debugger
: 导出自 debug
, 用于控制调试日志的输出。chalk
: 导出自 chalk
, 常用于在终端中输出彩色文字,支持链式调用,能够设置文本样式、颜色、背景色等。signale
: 导出自 signale
, 用于日志记录、状态报告以及处理其他 Node 模块和应用的输出渲染方式。portfinder
: 导出自 portfinder
, 常用于在判断端口是否被占用或者获取没有被占用的端口等场景。glob
: 导出自 glob
, 用于获取匹配对应规则的文件。pkgUp
: 导出自 pkg-up
, 查找最近的 package.json 文件。resolve
: 导出自 resolve
, 实现了 node 的 require.resolve() 算法, 提供了方便处理获取模块完整路径相关需求的方法。spawn
: 导出自 cross-spawn
, 已经封装好了 Node.js 子进程(child_process)模块下 spawn
函数的跨平台写法的相关细节, 直接使用其调用系统上的命令如 npm
即可。execa
: 导出自 execa
, 更好的子进程管理工具。相当于衍生一个 shell,传入的 command 字符串在该 shell 中直接处理。mkdirp
: 导出自 mkdirp
, node 中 mkdir -p
功能的实现, 用于在 Node.js 中递归式创建目录及其子目录。rimraf
: 导出自 rimraf
, node 中 rm -rf
功能的实现,yargs
: 导出自 yargs
, 用于创建交互式命令行工具,能够方便的处理命令行参数。yParser
: 导出自 yargs-parser
, yargs
使用的强大 option 解析器, 用于解析命令行参数。parser
: 导出自 @babel/parser
, 解析代码生成 AST 抽象语法树。traverse
: 导出自 @babel/traverse
, 对 AST 节点进行递归遍历。t
: 导出自 @babel/types
, 用于 AST 节点的 Lodash 式工具库。它包含了构造、验证以及变换 AST 节点的方法。 该工具库包含考虑周到的工具方法,对编写处理 AST 逻辑非常有用。内部工具方法
isBrowser
, 判断是否在浏览器环境。isWindows
, 判断当前是否是 windows 系统。isSSR
, whether SSR success in client。isLernaPackage
, 判断是否存在 lerna.json
文件。winPath
, 将文件路径转换为兼容 window 的路径,用于在代码中添加 require('/xxx/xxx.js')
之类的代码。winEOL
, 在 windows 环境下,很多工具都会把换行符 lf 自动改成 crlf, 为了测试精准需要将换行符转化一下。compatESModuleRequire
, 兼容 ESModule 以及 Require 为 Require。mergeConfig
, 对象合并。randomColor
, 随机生成颜色。delay
, 延迟函数。Generator
, mustache
模版代码生成。BabelRegister
, @babel/register
的简易封装。parseRequireDeps
, 获取特定文件的本地依赖。cleanRequireCache
, 清理特定 Module 在 require cache 以及 parent.children 中的引用。getWindowInitialProps
, 获取 window.g_initialProps。getFile
, 获取特定目录中文件的完整扩展名,javascript 文件的匹配顺序 ['.ts', '.tsx', '.js', '.jsx']
,css 文件的匹配顺序 ['.less', '.sass', '.scss', '.stylus', '.css']
。routeToChunkName
, transform route component into webpack chunkName。类型
ArgsType<T extends (...args: any[]) => any>
, 获取函数参数数组类型。PartialKeys<T>
, 找出 T 中类型是 undefined 的 key。PartialProps<T>
, 取出 T 中类型是 undefined 的属性。NodeEnv
: 联合类型 'development' | 'production' | 'test'。Omit<T, U>
, 排除 T 中的 U key。注:
api.utils
,还可通过 import { utils } from 'umi'
取到,通常用于非插件主入口的文件为 api.applyPlugins()
提供 type 参数的类型,包含三种:
为 api.describe()
提供 config.onChange 的类型,目前包含两种:
插件的启用方式,包含三种,
stage
的枚举类型,通常用于和 stage
的比较。
可以用到的环境变量。
umi/package.json
所在的文件夹路径