一、是什么

Plugin(Plug-in)是一种计算机应用程序,它和主应用程序互相交互,以提供特定的功能

是一种遵循一定规范的应用程序接口编写出来的程序,只能运行在程序规定的系统下,因为其需要调用原纯净系统提供的函数库或者数据

webpack中的plugin也是如此,plugin赋予其各种灵活的功能,例如打包优化、资源管理、环境变量注入等,它们会运行在 webpack 的不同阶段(钩子 / 生命周期),贯穿了webpack整个编译周期

目的在于解决loader 无法实现的其他事

配置方式

这里讲述文件的配置方式,一般情况,通过配置文件导出对象中plugins属性传入new实例对象。如下所示:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 访问内置的插件
module.exports = {
  ...
  plugins: [
    new webpack.ProgressPlugin(),
    new HtmlWebpackPlugin({ template: './src/index.html' }),
  ],
};

二、特性

其本质是一个具有apply方法javascript对象

apply 方法会被 webpack compiler调用,并且在整个编译生命周期都可以访问 compiler对象

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
 
class ConsoleLogOnBuildWebpackPlugin {
  apply(compiler) {
    compiler.hooks.run.tap(pluginName, (compilation) => {
      console.log('webpack 构建过程开始!');
    });
  }
}
 
module.exports = ConsoleLogOnBuildWebpackPlugin;

compiler hook 的 tap方法的第一个参数,应是驼峰式命名的插件名称

关于整个编译生命周期钩子,有如下:

  • entry-option :初始化 option
  • run
  • compile: 真正开始的编译,在创建 compilation 对象之前
  • compilation :生成好了 compilation 对象
  • make 从 entry 开始递归分析依赖,准备对每个模块进行 build
  • after-compile: 编译 build 过程结束
  • emit :在将内存中 assets 内容写到磁盘文件夹之前
  • after-emit :在将内存中 assets 内容写到磁盘文件夹之后
  • done: 完成所有的编译过程
  • failed: 编译失败的时候

三、常见的 Plugin

常见的plugin有如图所示:

下面介绍几个常用的插件用法:

HtmlWebpackPlugin

在打包结束后,⾃动生成⼀个 html ⽂文件,并把打包生成的js 模块引⼊到该 html 中

npm install --save-dev html-webpack-plugin
// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
 ...
  plugins: [
     new HtmlWebpackPlugin({
       title: "My App",
       filename: "app.html",
       template: "./src/html/index.html"
     }) 
  ]
};
<!--./src/html/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title><%=htmlWebpackPlugin.options.title%></title>
</head>
<body>
    <h1>html-webpack-plugin</h1>
</body>
</html>

在 html 模板中,可以通过 <%=htmlWebpackPlugin.options.XXX%> 的方式获取配置的值

更多的配置可以自寻查找

clean-webpack-plugin

删除(清理)构建目录

npm install --save-dev clean-webpack-plugin
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports = {
 ...
  plugins: [
    ...,
    new CleanWebpackPlugin(),
    ...
  ]
}

mini-css-extract-plugin

提取 CSS 到一个单独的文件

npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
 ...,
  module: {
   rules: [
    {
     test: /\.s[ac]ss$/,
     use: [
      {
       loader: MiniCssExtractPlugin.loader
     },
          'css-loader',
          'sass-loader'
        ]
   }
   ]
 },
  plugins: [
    ...,
    new MiniCssExtractPlugin({
     filename: '[name].css'
    }),
    ...
  ]
}

DefinePlugin

允许在编译时创建配置的全局对象,是一个webpack内置的插件,不需要安装

const { DefinePlugun } = require('webpack')
 
module.exports = {
 ...
    plugins:[
        new DefinePlugin({
            BASE_URL:'"./"'
        })
    ]
}

这时候编译template模块的时候,就能通过下述形式获取全局对象

<link rel="icon" href="<%= BASE_URL%>favicon.ico>"

CopyWebpackPlugin

复制文件或目录到执行区域,如vue的打包过程中,如果我们将一些文件放到public的目录下,那么这个目录会被复制到dist文件夹中

npm install copy-webpack-plugin -D
new CopyWebpackPlugin({
    parrerns:[
        {
            from: path.resolve(__dirname, 'src/assets'), // 源文件路径
            to: path.resolve(__dirname, 'dist/assets'), // 目标文件路径
            globOptions:{
                ignore:[
                    '**/index.html'
                ]
            }
        }
    ]
})

复制的规则在patterns属性中设置:

  • from:设置从哪一个源中开始复制
  • to:复制到的位置,可以省略,会默认复制到打包的目录下
  • globOptions:设置一些额外的选项,其中可以编写需要忽略的文件

四、 自定义Plugin

让我们来写一个简单的示例插件,生成一个叫做 assets.md 的新文件;文件内容是所有构建生成的文件的列表。这个插件大概像下面这样:

lass FileListPlugin {
  static defaultOptions = {
    outputFile: 'assets.md',
  };
 
  // 需要传入自定义插件构造函数的任意选项
  //(这是自定义插件的公开API)
  constructor(options = {}) {
    // 在应用默认选项前,先应用用户指定选项
    // 合并后的选项暴露给插件方法
    // 记得在这里校验所有选项
    this.options = { ...FileListPlugin.defaultOptions, ...options };
  }
 
  apply(compiler) {
    const pluginName = FileListPlugin.name;
 
    // webpack 模块实例,可以通过 compiler 对象访问,
    // 这样确保使用的是模块的正确版本
    // (不要直接 require/import webpack)
    const { webpack } = compiler;
 
    // Compilation 对象提供了对一些有用常量的访问。
    const { Compilation } = webpack;
 
    // RawSource 是其中一种 “源码”("sources") 类型,
    // 用来在 compilation 中表示资源的源码
    const { RawSource } = webpack.sources;
 
    // 绑定到 “thisCompilation” 钩子,
    // 以便进一步绑定到 compilation 过程更早期的阶段
    compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
      // 绑定到资源处理流水线(assets processing pipeline)
      compilation.hooks.processAssets.tap(
        {
          name: pluginName,
 
          // 用某个靠后的资源处理阶段,
          // 确保所有资源已被插件添加到 compilation
          stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE,
        },
        (assets) => {
          // "assets" 是一个包含 compilation 中所有资源(assets)的对象。
          // 该对象的键是资源的路径,
          // 值是文件的源码
 
          // 遍历所有资源,
          // 生成 Markdown 文件的内容
          const content =
            '# In this build:\n\n' +
            Object.keys(assets)
              .map((filename) => `- ${filename}`)
              .join('\n');
 
          // 向 compilation 添加新的资源,
          // 这样 webpack 就会自动生成并输出到 output 目录
          compilation.emitAsset(
            this.options.outputFile,
            new RawSource(content)
          );
        }
      );
    });
  }
}
 
module.exports = { FileListPlugin };
const { FileListPlugin } = require('./file-list-plugin.js');
 
// 在 webpack 配置中使用自定义的插件:
module.exports = {
  // …
 
  plugins: [
    // 添加插件,使用默认选项
    new FileListPlugin(),
 
    // 或者:
 
    // 使用任意支持的选项
    new FileListPlugin({
      outputFile: 'my-assets.md',
    }),
  ],
};

总结

在Webpack中,插件(plugin)是用来扩展和定制构建过程的工具,可以用于处理和优化资源、自动化任务、注入变量等。

插件一般是一个具有apply方法的JavaScript对象,通过在Webpack的配置中配置插件,可以在构建过程中执行额外的操作。

以下是一些常用的Webpack插件及其作用:

  1. HtmlWebpackPlugin:用于自动生成HTML文件,并将打包生成的所有资源(如CSS、JS文件)自动注入到生成的HTML文件中。
  2. MiniCssExtractPlugin:用于将CSS代码从打包生成的JS文件中提取出来,创建一个单独的CSS文件,可以实现CSS的异步加载和浏览器缓存优化。
  3. TerserWebpackPlugin:用于对JS代码进行压缩和混淆,减小文件体积,提高加载速度。
  4. OptimizeCSSAssetsWebpackPlugin:用于对提取出的CSS进行压缩和优化
  5. CleanWebpackPlugin:用于在构建之前清空输出目录,避免旧文件的干扰。
  6. CopyWebpackPlugin:用于将静态文件从源目录复制到输出目录,例如将图片、字体等文件复制到打包后的文件夹中。
  7. DefinePlugin:用于定义全局变量,可以在代码中直接使用这些变量,例如配置环境变量、区分开发环境和生产环境等。
  8. HotModuleReplacementPlugin:用于启用模块热更新,实现在开发过程中无需刷新页面即可看到最新变更的效果。
  9. CompressionWebpackPlugin:用于对打包生成的文件进行gzip压缩,减小文件体积,提升网络传输速度。
  10. ProvidePlugin:用于自动加载模块,当代码中使用到某个模块时,会自动将模块引入,无需手动import。

这只是一小部分常用的Webpack插件,实际上还有很多其他的插件可以根据需要进行使用和定制。使用合适的插件可以大大提高Webpack的功能和效率,以及优化构建过程和最终生成的资源文件。

扩展阅读