Vue 项目之 Webpack 的 Plugins(1)

763 阅读5分钟

「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

前面我们已经讲了项目中关于 jscssimg 以及 font 文件的打包,这几类文件也是我们开发中最常用的资源(当然,对于 Vue 的项目来说,还有 .vue 文件的使用,如何对它进行打包呢?我们会使用对应的 loader 并结合一个 plugin 来对其做打包,具体我们后面会讲。而开发 React 时,还会使用 .jsx 文件,这些都是特殊场景下使用的文件类型)。对这几类文件的打包配置也是 Webpack 最基本的使用方式。

在开始本节内容之前,我们先来做下准备工作:

  1. 删除 webpack_资源 目录下的 buildnode_modules 文件夹;

  2. 拷贝一份 webpack_资源 目录,并重命名为 webpack_插件

  3. 打开 VS Code 的终端,切换目录到 webpack_插件 下,运行 npm install 安装当前项目(webpack_插件)所需依赖,安装完成后,项目目录如下:

    image-20211113232213867

当前,我们的项目中主要还存在两个不太好的地方:

  1. 每次打包前都需要手动删除上次打包出来的文件夹(我们这里是 ./build),每次手动删除有点麻烦;
  2. 打包出来的文件夹下缺少关键的 index.html 文件(我们说过,静态资源中需要有一个 .html 文件作为入口文件,虽然项目目录下有 index.html 文件,但项目目录下的这些文件一般是额外的配置,我们不会对它们进行部署,我们只会部署打包出来的文件夹);

先来讨论第一个问题。我们现在每次打包之前可能需要先把之前打包的东西删掉,那如果希望它能自动删掉该怎么办呢?你可能会想,是不是也有对应的 loader 来帮助我们实现呢?如果这样想就不对了,因为我们前面讲过,当我们加载模块的时候需要用到对应的 loader,但我们现在想做的事情并不是加载某个模块,而是把项目中的某个文件夹在某个时刻(即打包之前)给删除掉,那就与 loader 没有关系了,这时就需要使用插件(plugin)了。插件是干嘛的呢?简单来说,只要是 loader 做不了的事情,而你又想在 webpack 中的某个时刻做某件事,那么都可以使用插件来完成。插件的功能非常强大,它贯穿于 webpack 的整个生命周期,不仅在加载模块的时候会用到,在其它很多地方,包括在加载入口、出口配置时本质上都会转成插件来进行使用的(这些都可以通过 webpack 的源码看到)。

因此,Webpack 的另一个核心是 Plugin,官方文档中有这样一段对 Plugin 的描述1

While loaders are used to transform certain types of modules, plugins can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables.

上面表达的含义翻译过来就是:

  • Loaders 用来转换特定的模块类型

  • Plugins 可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等等;

    image-20211113154941483

    上图表达的意思是,通过 css-loadercss 文件做了打包(我们当前是把 css 代码通过 <style> 元素注入进 HTML 文档中的,并没有做 css 代码的提取),打包之后可以利用插件把这些 css 代码提取到一个独立的文件中。后面我们会讲如何提取 css 代码到独立的文件中。

1. CleanWebpackPlugin

前面我们每次修改完配置重新打包时,都需要手动删除上次构建出来的文件夹,其实,我们可以借助于一个插件来帮助我们完成这一操作,这个插件就是 CleanWebpackPlugin。默认情况下,这个插件将移除 webpack 配置中 output.path 对应的目录下的所有文件,以及所有在每次成功重建之后未被使用的 webpack 资源。

首先,我们来安装这个插件:

npm install --save-dev clean-webpack-plugin

之后在 webpack.config.js 文件中的插件(plugins)选项中进行配置:

...
// 与 loader 不一样,插件必须手动导入
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  ...
  plugins: [
    new CleanWebpackPlugin()
  ]
}

因为这个插件导出的是一个包含一个名为 CleanWebpackPlugin 类的对象,所以我们导入时需要拿到这个对象中的类(一般情况下,插件都会封装成一个 class,到时候会通过里面的 hook 进行回调,来执行插件里面的代码,这些就涉及到自定义插件和源码相关的内容了,这里简单了解即可,总之,插件一般提供的是一个类(当然,也可以是一个函数),我们只要使用这个类创建对象即可)。插件的配置是在配置文件导出对象的 plugins 选项中编写的,plugins 选项对应一个数组,数组里面需要放的是一个个的插件对象(其实在 webpack 源码中,是拿到我们导出的这个对象,然后取到里面的 plugins,之后再做 for 循环来进行注入,之后会根据不同的 hook 的生命周期来回调插件中的对象的某个方法)。

配置完成后,为了方便查看效果,我们可以先把 plugins 选项中的配置注释掉,然后先来打包一下生成 build 文件夹(打包输出目录),再在这个 build 文件夹下新建一个 abc.txt 文件,再来进行打包,你会发现,再次打包过后,abc.txt 文件依然还在。现在,我们把 plugins 选项中的配置取消注释,即使用这个插件后再来打包,你会发现,这次 abc.txt 文件就被删除了。因为这个插件在我们打包时会先把打包输出的文件夹下的文件都删除掉,然后再生成新的打包文件。

Footnotes

  1. 详见 webpack.js.org/concepts/#p…