Webpack插件浅析

246 阅读4分钟

前言

webpack 插件是 webpack 重要的组成部分,它是对 webapck 功能的一个扩展,并可以完成 loader 无法完成的工作。

plugin 和 loader 的区别

在刚学 webpack 的时候,我常常对 plugin 和 loader 傻傻分不清,经过一段时间的了解之后,发现两者是很好区分的(这个也是面试官很爱的考题哟)

  • loader 是一个转译器,将 A 文件转译成 B 文件,比如将 A.less 转换成 B.css,是单纯的文件转换。
  • plugin 是一个扩展器,它丰富了 webpack 本身,对于 webapck 的每个阶段都可以进行插入,它是基于 webpack 的事件机制,在 webpack 某某些节点执行任务。

plugin 的用法

语法

plugins: [pluginA, pluginB, pluginC...]

数组中的插件是调用 new 方法得到的实例

  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]

介绍几个常用的 webpack 插件

imagemin-webpack-plugin

This is a simple plugin that uses Imagemin to compress all images in your project.

一个用于压缩图片的插件

安装

npm install imagemin-webpack-plugin
yarn add imagemin-webpack-plugin

配置

var ImageminPlugin = require('imagemin-webpack-plugin').default
// 如果是 es6:
// import ImageminPlugin from 'imagemin-webpack-plugin'

module.exports = {
  plugins: [
    // 请保证这个插件使用在其他可以插入的图片的插件之后
    new ImageminPlugin({
      disable: process.env.NODE_ENV !== 'production', // 在开发模式禁用
      pngquant: {
        quality: '95-100'
      }
    })
  ]
}

文档

clean-webpack-plugin

A webpack plugin to remove/clean your build folder(s). 一个用于清理编译文件的插件

作用:在每次编译之前,清除上一次编译后产生的文件

安装

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

配置

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

const webpackConfig = {
    plugins: [
        new CleanWebpackPlugin(),
    ],
};

文档

ProvidePlugin

懒人专用插件

自动加载模块,你只需要把常用的模块在插件中配置一次,在使用过程中就可以免去 importrequire

安装

免安装,因为是 webpack 内置的插件

配置

const webpackConfig = {
    plugins: [
        new webpack.ProvidePlugin({
          identifier: ['module1', 'property1'],
          Vue: ['vue/dist/vue.esm.js', 'default'], // Vue
          React'react', // react
          $: 'jquery' // jquery
          // ...
        }),
    ],
};

文档

purifycss-webpack

This plugin uses PurifyCSS to remove unused selectors from your CSS.

一个用于删除多余的 css 代码的插件,注意要搭配 extract-text-webpack-plugin 一起使用

安装

npm i -D purifycss-webpack purify-css
yarn add --dev purifycss-webpack purify-css

配置

const path = require('path');
const glob = require('glob');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PurifyCSSPlugin = require('purifycss-webpack');

module.exports = {
  entry: {...},
  output: {...},
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          fallbackLoader: 'style-loader',
          loader: 'css-loader'
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('[name].[contenthash].css'),
    // Make sure this is after ExtractTextPlugin!
    new PurifyCSSPlugin({
      // Give paths to parse for rules. These should be absolute!
      paths: glob.sync(path.join(__dirname, 'app/*.html')),
    })
  ]
};

文档

自己写个组件

看了上面的几个组件,是不是也想试试自己写一个呢?

不过在编写 webpack 插件之前,需要有一定的 webpack 基础,如果对 webpack 还不熟悉的同学,可以看看我这两篇文章哟


在写插件之前,我们先了解一下,webpack 要求的写插件规范吧

一个官方的例子

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

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

从例子中我们可以看到

  1. 需要一个 pluginName 插件名称
  2. 定义的插件是一个类
  3. 这个类里面要有一个 apply 方法,这个方法会被 webapck 在编译过程中调用
  4. 通过给 hooks 定义处理函数,实现插件的功能

下面我们写一个可以打印出 webpack 重要的操作流程的插件

基础知识:webpack 的整体流程可以分为 env > init > compiler > make > seal > emit > done

  • env 和 init 阶段负责初始化环境和激活 webpack 内部插件
  • compiler 阶段是编译的开始
  • make 阶段 webpack 会进行依赖分析和收集
  • seal 阶段 webpack 会生成 chunk 文件
  • emit 阶段 webpack 会把 chunks 写入硬盘
  • done 阶段,顾名思义就会 webpack 工作完成啦

如果对上面的流程不熟悉的话,不妨看看我的两篇文章哟

操作流程打印插件

代码

const pluginName = 'ConsoleLogProgressPlugin';

class ConsoleLogProgressPlugin {
  apply(compiler) {
    console.log()
    compiler.hooks.initialize.tap(pluginName, () => {
      console.log('我发现 webpack 在准备环境')
    });
    compiler.hooks.compile.tap(pluginName, () => {
      console.log('我发现 webpack 开始编译')
    });
    compiler.hooks.afterCompile.tap(pluginName, () => {
      console.log('我发现 webpack 编译完成')
    });
    compiler.hooks.make.tap(pluginName, () => {
      console.log('我发现 webpack 开始收集依赖')
    });
    compiler.hooks.finishMake.tap(pluginName, () => {
      console.log('我发现 webpack 开始收集依赖完成')
    });
    compiler.hooks.compilation.tap(pluginName, (compilation) => {
      compilation.hooks.seal.tap(pluginName, () => {
        console.log('我发现 webpack 开始打包 chunk')
      });
    })
    compiler.hooks.emit.tap(pluginName, () => {
      console.log('我发现 webpack 发射文件')
    });
    compiler.hooks.done.tap(pluginName, () => {
      console.log('我发现 webpack 搞定了')
    });
  }
}

module.exports = ConsoleLogProgressPlugin

配置

const ConsoleLogProgressPlugin = require('./plugin/ConsoleLogProgressPlugin')

module.exports = {
  entry: './src/index.js',
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
      }
    ],
  },
  plugins: [
    new ConsoleLogProgressPlugin(),
  ],
};

效果

image.png

最后

总结一下:(引用了自己的前言)

webpack 插件是 webpack 重要的组成部分,它是对 webapck 功能的一个扩展,并可以完成 loader 无法完成的工作。


感谢各位看官看到最后,码字不易,如果觉得这篇文章对你有用,请动动你们的小鼠标点个赞吧。

如果觉得写得不好的地方,也欢迎指出。