获取当前执行命令所带的参数,例如命令 taro upload --remote xxx.xxx.xxx.xxx,则 ctx.runOpts 值为:
{ _: ['upload'], options: { remote: 'xxx.xxx.xxx.xxx' }, isHelp: false } ctx.helper为包 @tarojs/helper 的快捷使用方式,包含其所有 API。
ctx.initialConfig获取项目配置。
ctx.plugins获取当前所有挂载的插件。
插件方法Taro 的插件架构基于 Tapable。
ctx.register(hook: IHook)注册一个可供其他插件调用的钩子,接收一个参数,即 Hook 对象。
一个 Hook 对象类型如下:
interface IHook { // Hook 名字,也会作为 Hook 标识 name: string // Hook 所处的 plugin id,不需要指定,Hook 挂载的时候会自动识别 plugin: string // Hook 回调 fn: Function before?: string stage?: number }通过 ctx.register 注册过的钩子需要通过方法 ctx.applyPlugins 进行触发。
我们约定,按照传入的 Hook 对象的 name 来区分 Hook 类型,主要为以下三类:
事件类型 Hook,Hook name 以 on 开头,如 onStart,这种类型的 Hook 只管触发而不关心 Hook 回调 fn 的值,Hook 的回调 fn 接收一个参数 opts ,为触发钩子时传入的参数
修改类型 Hook,Hook name 以 modify 开头,如 modifyBuildAssets,这种类型的 Hook 触发后会返回做出某项修改后的值,Hook 的回调 fn 接收两个参数 opts 和 arg ,分别为触发钩子时传入的参数和上一个回调执行的结果
添加类型 Hook,Hook name 以 add 开头,如 addConfig,这种类型 Hook 会将所有回调的结果组合成数组最终返回,Hook 的回调 fn 接收两个参数 opts 和 arg ,分别为触发钩子时传入的参数和上一个回调执行的结果
如果 Hook 对象的 name 不属于以上三类,则该 Hook 表现情况类似事件类型 Hook。
钩子回调可以是异步也可以是同步,同一个 Hook 标识下一系列回调会借助 Tapable 的 AsyncSeriesWaterfallHook 组织为异步串行任务依次执行。
ctx.registerMethod(arg: string | { name: string, fn?: Function }, fn?: Function)向 ctx 上挂载一个方法可供其他插件直接调用。
主要调用方式:
ctx.registerMethod('methodName') ctx.registerMethod('methodName', () => { // callback }) ctx.registerMethod({ name: 'methodName' }) ctx.registerMethod({ name: 'methodName', fn: () => { // callback } })其中方法名必须指定,而对于回调函数则存在两种情况。
指定回调函数则直接往 ctx 上进行挂载方法,调用时 ctx.methodName 即执行 registerMethod 上指定的回调函数。
不指定回调函数则相当于注册了一个 methodName 钩子,与 ctx.register 注册钩子一样需要通过方法 ctx.applyPlugins 进行触发,而具体要执行的钩子回调则通过 ctx.methodName 进行指定,可以指定多个要执行的回调,最后会按照注册顺序依次执行。
内置的编译过程中的 API 如 ctx.onBuildStart 等均是通过这种方式注册。
ctx.registerCommand(hook: ICommand)注册一个自定义命令。
interface ICommand { // 命令别名 alias?: string, // 执行 taro <command> --help 时输出的 options 信息 optionsMap?: { [key: string]: string }, // 执行 taro <command> --help 时输出的使用例子的信息 synopsisList?: string[] }使用方式:
ctx.registerCommand({ name: 'create', fn () { const { type, name, description } = ctx.runOpts const { chalk } = ctx.helper const { appPath } = ctx.paths if (typeof name !== 'string') { return console.log(chalk.red('请输入需要创建的页面名称')) } if (type === 'page') { const Page = require('../../create/page').default const page = new Page({ pageName: name, projectDir: appPath, description }) page.create() } } }) ctx.registerPlatform(hook: IPlatform)注册一个编译平台。
interface IFileType { templ: string style: string script: string config: string } interface IPlatform extends IHook { // 编译后文件类型 fileType: IFileType // 编译时使用的配置参数名 useConfigName: String }使用方式:
ctx.registerPlatform({ name: 'alipay', useConfigName: 'mini', async fn ({ config }) { const { appPath, nodeModulesPath, outputPath } = ctx.paths const { npm, emptyDirectory } = ctx.helper emptyDirectory(outputPath) // 准备 miniRunner 参数 const miniRunnerOpts = { ...config, nodeModulesPath, buildAdapter: config.platform, isBuildPlugin: false, globalObject: 'my', fileType: { templ: '.awml', style: '.acss', config: '.json', script: '.js' }, isUseComponentBuildPage: false } ctx.modifyBuildTempFileContent(({ tempFiles }) => { const replaceKeyMap = { navigationBarTitleText: 'defaultTitle', navigationBarBackgroundColor: 'titleBarColor', enablePullDownRefresh: 'pullRefresh', list: 'items', text: 'name', iconPath: 'icon', selectedIconPath: 'activeIcon', color: 'textColor' } Object.keys(tempFiles).forEach(key => { const item = tempFiles[key] if (item.config) { recursiveReplaceObjectKeys(item.config, replaceKeyMap) } }) }) // build with webpack const miniRunner = await npm.getNpmPkg('@tarojs/mini-runner', appPath) await miniRunner(appPath, miniRunnerOpts) } }) ctx.applyPlugins(args: string | { name: string, initialVal?: any, opts?: any })触发注册的钩子。
传入的钩子名为 ctx.register 和 ctx.registerMethod 指定的名字。
这里值得注意的是如果是修改类型和添加类型的钩子,则拥有返回结果,否则不用关心其返回结果。