Plugin Hooks

本章节描述了 Builder 插件提供的生命周期钩子。

概览

通用钩子

  • modifyBuilderConfig:修改传递给 Builder 的配置项。
  • modifyBundlerChain (实验性):通过 chain api 修改 webpack / Rspack 配置。
  • modifyWebpackChain:修改 webpack chain 配置。
  • modifyWebpackConfig:修改最终的 webpack 配置对象。
  • modifyRspackConfig:修改最终的 Rspack 配置对象。
  • onBeforeCreateCompiler:在创建 compiler 实例前调用。
  • onAfterCreateCompiler:在创建 compiler 实例后、执行构建前调用。

构建钩子:仅在执行 build 方法构建生产环境产物时调用。

  • onBeforeBuild:在执行生产环境构建前调用。
  • onAfterBuild:在执行生产环境构建后调用,可以获取到构建结果信息。

开发服务钩子:仅在执行 startDevServer 方法运行开发服务器时调用。

  • onBeforeStartDevServer:在启动开发服务器前调用。
  • onAfterStartDevServer:在启动开发服务器后调用。
  • onDevCompileDone:在每次开发环境构建结束后调用。

其他钩子

  • onExit:在进程即将退出时调用。

通用钩子

modifyBuilderConfig

修改传递给 Builder 的配置项,你可以直接修改传入的 config 对象,也可以返回一个新的对象来替换传入的对象。

  • 类型
type ModifyWebpackChainUtils = {
  mergeBuilderConfig: typeof mergeBuilderConfig;
};

function ModifyBuilderConfig(
  callback: (
    config: BuilderConfig,
    utils: ModifyWebpackChainUtils,
  ) => PromiseOrNot<BuilderConfig | void>,
): void;
  • Example
export default () => ({
  setup: api => {
    api.modifyBuilderConfig((config, { mergeBuilderConfig }) => {
      config.html = config.html || {};
      config.html.title = 'Hello World!';
      return mergeBuilderConfig(config, {
        source: { preEntry: 'foo.js' },
      });
    });
  },
});

modifyBundlerChain 实验性

什么是 BundlerChain

Bundler chain 是 webpack chain 的子集,其中包含一部分 webpack chain API,你可以用它来同时修改 webpack 和 Rspack 的配置。

通过 bundler chain 修改的配置,在 webpack 和 Rspack 构建时均可生效。需要注意的是,bundler chain 只支持修改 webpack 和 Rspack 间无差异部分的配置。如,修改 devtool 配置项(webpack 和 Rspack 的 devtool 属性值类型相同),或添加一个Rspack 兼容的 webpack 插件。

modifyBundlerChain 用于调用 bundler chain 来修改 webpack / Rspack 的配置。你在使用 webpack-provider 或 rspack-provider 时都可以使用该 hook。

  • 类型
type ModifyBundlerChainUtils = {
  env: NodeEnv;
  isProd: boolean;
  target: BuilderTarget;
  isServer: boolean;
  isWebWorker: boolean;
  CHAIN_ID: ChainIdentifier;
  HtmlPlugin: typeof import('html-webpack-plugin');
  bundler: {
    // 取决于 bundler 类型
    BannerPlugin: typeof webpack.BannerPlugin | typeof rspack.BannerPlugin;
    DefinePlugin: typeof webpack.DefinePlugin | typeof rspack.DefinePlugin;
  }
};

function ModifyBundlerChain(
  callback: (
    chain: BundlerChain,
    utils: ModifyBundlerChainUtils,
  ) => Promise<void> | void,
): void;
  • Example
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';

export default () => ({
  setup: api => {
    api.modifyBundlerChain((chain, utils) => {
      if (utils.env === 'development') {
        chain.devtool('eval');
      }

      chain.plugin('bundle-analyze').use(BundleAnalyzerPlugin);
    });
  },
});

modifyWebpackChain

通过 webpack chain 来修改 webpack 配置。该方法仅在使用 webpack-provider 时调用。

  • 类型
type ModifyWebpackChainUtils = {
  env: NodeEnv;
  isProd: boolean;
  target: BuilderTarget;
  webpack: typeof import('webpack');
  isServer: boolean;
  isWebWorker: boolean;
  CHAIN_ID: ChainIdentifier;
  getCompiledPath: (name: string) => string;
  HtmlWebpackPlugin: typeof import('html-webpack-plugin');
};

function ModifyWebpackChain(
  callback: (
    chain: WebpackChain,
    utils: ModifyWebpackChainUtils,
  ) => Promise<void> | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.modifyWebpackChain((chain, utils) => {
      if (utils.env === 'development') {
        chain.devtool('eval');
      }
    });
  },
});

modifyWebpackConfig

修改最终的 webpack 配置对象,你可以直接修改传入的 config 对象,也可以返回一个新的对象来替换传入的对象。该方法仅在使用 webpack-provider 时调用。

该方法的调用时机晚于 modifyWebpackChain 钩子。

  • 类型
type ModifyWebpackConfigUtils = {
  env: NodeEnv;
  isProd: boolean;
  target: BuilderTarget;
  webpack: typeof import('webpack');
  isServer: boolean;
  isWebWorker: boolean;
  CHAIN_ID: ChainIdentifier;
  getCompiledPath: (name: string) => string;
  HtmlWebpackPlugin: typeof import('html-webpack-plugin');
  addRules: (rules: RuleSetRule | RuleSetRule[]) => void;
  prependPlugins: (
    plugins: WebpackPluginInstance | WebpackPluginInstance[],
  ) => void;
  appendPlugins: (
    plugins: WebpackPluginInstance | WebpackPluginInstance[],
  ) => void;
  removePlugin: (pluginName: string) => void;
};

function ModifyWebpackConfig(
  callback: (
    config: WebpackConfig,
    utils: ModifyWebpackConfigUtils,
  ) => Promise<WebpackConfig | void> | WebpackConfig | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.modifyWebpackConfig((config, utils) => {
      if (utils.env === 'development') {
        config.devtool = 'eval';
      }
    });
  },
});

modifyRspackConfig

修改最终的 Rspack 配置对象,你可以直接修改传入的 config 对象,也可以返回一个新的对象来替换传入的对象。该方法仅在使用 rspack-provider 时调用。

  • 类型
type ModifyRspackConfigUtils = {
  env: NodeEnv;
  isProd: boolean;
  target: BuilderTarget;
  isServer: boolean;
  isWebWorker: boolean;
  getCompiledPath: (name: string) => string;
  rspack: typeof import('@rspack/core');
};

function ModifyRspackConfig(
  callback: (
    config: RspackConfig,
    utils: ModifyRspackConfigUtils,
  ) => Promise<RspackConfig | void> | RspackConfig | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.modifyRspackConfig((config, utils) => {
      if (utils.env === 'development') {
        config.devtool = 'eval';
      }
    });
  },
});

onBeforeCreateCompiler

onBeforeCreateCompiler 是在创建底层 Compiler 实例前触发的回调函数,当你执行 builder.startDevServerbuilder.buildbuilder.createCompiler 时,都会调用此钩子。

你可以通过 bundlerConfigs 参数获取到底层打包工具的最终配置数组:

  • 如果当前打包工具为 webpack,则获取到的是 webpack 配置数组。
  • 如果当前打包工具为 Rspack,则获取到的是 Rspack 配置数组。
  • 配置数组中可能包含一份或多份配置,这取决于你是否开启了 SSR 等功能。

你可以通过 bundlerConfigs 参数获取到底层打包工具的最终配置对象。

  • 类型
function OnBeforeCreateCompiler(
  callback: (params: {
    bundlerConfigs: WebpackConfig[] | RspackConfig[];
  }) => Promise<void> | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.onBeforeCreateCompiler(({ bundlerConfigs }) => {
      console.log('the bundler config is ', bundlerConfigs);
    });
  },
});

onAfterCreateCompiler

onAfterCreateCompiler 是在创建 Compiler 实例后、执行构建前触发的回调函数,当你执行 builder.startDevServerbuilder.buildbuilder.createCompiler 时,都会调用此钩子。

你可以通过 compiler 参数获取到 Compiler 实例对象:

  • 如果当前打包工具为 webpack,则获取到的是 webpack Compiler 对象。

  • 如果当前打包工具为 Rspack,则获取到的是 Rspack Compiler 对象。

  • 类型

function OnAfterCreateCompiler(callback: (params: {
  compiler: Compiler | MultiCompiler;
}) => Promise<void> | void;): void;
  • Example
export default () => ({
  setup: api => {
    api.onAfterCreateCompiler(({ compiler }) => {
      console.log('the compiler is ', compiler);
    });
  },
});

构建钩子

onBeforeBuild

onBeforeBuild 是在执行生产环境构建前触发的回调函数,你可以通过 bundlerConfigs 参数获取到底层打包工具的最终配置数组:

  • 如果当前打包工具为 webpack,则获取到的是 webpack 配置数组。

  • 如果当前打包工具为 Rspack,则获取到的是 Rspack 配置数组。

  • 配置数组中可能包含一份或多份配置,这取决于 Builder 当前 target 配置的值。

  • 类型

function OnBeforeBuild(
  callback: (params: {
    bundlerConfigs?: WebpackConfig[] | RspackConfig[];
  }) => Promise<void> | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.onBeforeBuild(({ bundlerConfigs }) => {
      console.log('the bundler config is ', bundlerConfigs);
    });
  },
});

onAfterBuild

onAfterBuild 是在执行生产环境构建后触发的回调函数,你可以通过 stats 参数获取到构建结果信息:

  • 如果当前打包工具为 webpack,则获取到的是 webpack Stats。

  • 如果当前打包工具为 Rspack,则获取到的是 Rspack Stats。

  • 类型

function OnAfterBuild(
  callback: (params: { stats?: Stats | MultiStats }) => Promise<void> | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.onAfterBuild(({ stats }) => {
      console.log(stats?.toJson());
    });
  },
});

开发服务钩子

onBeforeStartDevServer

在启动开发服务器前调用。

  • 类型
function OnBeforeStartDevServer(callback: () => Promise<void> | void): void;
  • Example
export default () => ({
  setup: api => {
    api.onBeforeStartDevServer(() => {
      console.log('before start!');
    });
  },
});

onAfterStartDevServer

在启动开发服务器后调用,你可以通过 port 参数获得开发服务器监听的端口号。

  • 类型
function OnAfterStartDevServer(
  callback: (params: { port: number }) => Promise<void> | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.onAfterStartDevServer(({ port }) => {
      console.log('this port is: ', port);
    });
  },
});

onDevCompileDone

在每次开发环境构建结束后调用,你可以通过 isFirstCompile 来判断是否为首次构建。

  • 类型
function OnDevCompileDone(
  callback: (params: { isFirstCompile: boolean }) => Promise<void> | void,
): void;
  • Example
export default () => ({
  setup: api => {
    api.onDevCompileDone(({ isFirstCompile }) => {
      if (isFirstCompile) {
        console.log('first compile!');
      } else {
        console.log('re-compile!');
      }
    });
  },
});

其他钩子

onExit

在进程即将退出时调用,这个钩子只能执行同步代码。

  • 类型
function OnExit(callback: () => void): void;
  • Example
export default () => ({
  setup: api => {
    api.onExit(() => {
      console.log('exit!');
    });
  },
});