webpack中plugin

183 阅读4分钟

一、定义

在 Webpack 中,Plugin(插件)  是用来扩展 Webpack 功能的 JavaScript 模块,它可以在 Webpack 构建流程的不同生命周期(钩子/Hooks)中执行自定义任务。

(1)Plugin 的本质

  • Plugin 是一个 JavaScript (或构造函数),必须实现 apply(compiler) 方法。
  • Webpack 在运行时会自动调用 apply 方法,并传入 compiler 对象,让插件可以访问 Webpack 的构建流程。
  • 插件可以监听 Webpack 的生命周期钩子(Hooks) ,并在特定时机执行自定义逻辑(如修改输出、优化资源、生成额外文件等)。

(2)Plugin 的核心作用

  1. 优化构建流程(如压缩代码、拆分代码、Tree Shaking)
  2. 资源管理(如自动生成 HTML、拷贝静态文件、提取 CSS)
  3. 增强功能(如热更新 HMR、分析打包体积、注入环境变量)
  4. 自定义构建行为(如修改打包后的文件、生成 manifest 文件)

二、常见有哪些plugin

  1. 基础 Plugin

    • HtmlWebpackPlugin:自动生成 HTML 文件,并自动注入打包后的 bundle
    • CleanWebpackPlugin:在每次构建前清理输出目录
    • DefinePlugin:定义编译时可用的全局常量
  2. 优化类 Plugin

    • MiniCssExtractPlugin:将 CSS 提取到单独的文件中
    • CompressionWebpackPlugin:生成 gzip 压缩的资源文件
    • TerserWebpackPlugin:JavaScript 代码压缩优化
  3. 开发辅助 Plugin

    • HotModuleReplacementPlugin:启用热模块替换(HMR)
    • BundleAnalyzerPlugin:可视化分析打包文件大小
    • ForkTsCheckerWebpackPlugin:在单独进程中进行 TypeScript 类型检查
  4. 高级功能 Plugin

    • DllPlugin 和 DllReferencePlugin:用于实现动态链接库,提升构建速度
    • ModuleFederationPlugin:实现微前端架构的模块联邦
    • CopyWebpackPlugin:复制文件或目录到构建目录

重点介绍一下DllPlugin 和DllReferencePlugin

  1. 背景: 在大型项目中,我们通常有很多第三方库(如react, lodash等),这些库的代码一般不会频繁改动。但是,每次构建时Webpack都要重新解析和构建这些代码,导致构建速度变慢。DllPlugin和DllReferencePlugin就是为了解决这个问题而设计的。它们通过预编译第三方库,将其打包成一个动态链接库(DLL),然后在项目构建时直接引用这个预编译好的库,从而避免重复构建。
  2. DllPlugin:作用:用于打包第三方库,生成一个动态链接库(DLL)文件,同时还会生成一个manifest.json文件(描述哪些库被打包进了DLL)。配置位置:通常在一个单独的webpack配置文件中使用(比如webpack.dll.config.js),然后通过运行这个配置文件来生成DLL文件。配置示例(webpack.dll.config.js):
const webpack = require('webpack');
const path = require('path');
module.exports = {
    entry: {vendor: ['react', 'react-dom', 'lodash'] // 指定要打包的第三方库},
    output: {
        path: path.join(__dirname, 'dll'),
        filename: '[name].dll.js',library: '[name]_dll' // 暴露出的全局变量名
     },
    plugins: [
        new webpack.DllPlugin({path: path.join(__dirname, 'dll', '[name]-manifest.json'), // manifest.json文件的输出路径name: '[name]_dll' // 必须与output.library保持一致})
    ]};

运行这个配置后,会在dll目录下生成vendor.dll.js和vendor-manifest.json。、

  1. DllReferencePlugin:作用:在项目构建的配置中引用DllPlugin生成的manifest.json文件,告诉Webpack哪些库不需要打包,而是从DLL中引用。配置位置:在项目的主webpack配置文件中使用(比如webpack.config.js)。配置示例(webpack.config.js):
module.exports = {// ...其他配置
    plugins: [
        new webpack.DllReferencePlugin({manifest: path.join(__dirname, 'dll', 'vendor-manifest.json')})]};
  1. 使用步骤:a. 创建一个单独的webpack配置文件(如webpack.dll.config.js)用于打包DLL,并运行它(例如:webpack --config webpack.dll.config.js)。b. 在主配置文件中(webpack.config.js)使用DllReferencePlugin引用生成的manifest文件。c. 在HTML中手动引入生成的DLL文件(vendor.dll.js),或者使用add-asset-html-webpack-plugin插件自动引入。
  2. 注意事项:- 当DLL中的库需要更新时,需要重新运行DLL的构建。- 如果修改了DLL配置中的entry,需要重新生成DLL,否则可能会引用不到。- 在开发环境和生产环境都可以使用,但通常用于开发环境以提升构建速度。
  3. 在Webpack 5中的情况:Webpack 5已经内置了更强大的缓存机制,并且推荐使用“hard-source-webpack-plugin”或者Webpack 5自带的持久性缓存(cache: { type: 'filesystem' })来提升构建性能。因此,在Webpack 5中,DLLPlugin的使用已经减少。但是,对于特别大型的项目,如果缓存还不能满足性能要求,依然可以使用DLLPlugin。
  4. 总结:DllPlugin和DllReferencePlugin通过分离第三方库来提升构建速度,但需要额外的配置步骤。在Webpack 5中,可以考虑使用新的缓存机制来替代。
 // webpack.config.js
module.exports = {
  cache: {
    type: 'filesystem',  // 启用持久化缓存
    buildDependencies: {
      config: [__filename] // 配置文件变更时自动失效缓存
    }
  },
  // 替代 DLL 的优化配置
  optimization: {
    moduleIds: 'deterministic',
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors'
        }
      }
    }
  }
}

三、如何自定义plugin

// 自定义插件示例:在构建完成后输出提示信息
class MyWebpackPlugin {
  // 可接收配置参数
  constructor(options) {
    this.options = options || {};
  }

  // apply 方法会被 webpack compiler 调用
  apply(compiler) {
    // 注册钩子函数
    compiler.hooks.done.tap('MyWebpackPlugin', (stats) => {
      console.log('构建已完成!');
      if (this.options.message) {
        console.log(this.options.message);
      }
    });

    // 更多钩子示例:在emit阶段(生成资源到output目录之前)执行
    compiler.hooks.emit.tapAsync('MyWebpackPlugin', (compilation, callback) => {
      // compilation 对象包含当前构建的所有信息
      console.log('准备生成资源文件...');
      // 可以修改compilation.assets来添加或修改资源
      callback();
    });
  }
}

// 使用方式
module.exports = {
  // ...其他配置
  plugins: [
    new MyWebpackPlugin({
      message: '这是我的自定义插件!'
    })
  ]
};