plugin的理解与使用

一、plugin是什么?

plugin插件,能够赋予webpack各种灵活的功能,例如打包优化、资源管理、环境变量注入等,他们会被指定在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' }),
  ],
};

二、plugin特性

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

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

compiler 钩子

Compiler 模块是 webpack 的主要引擎,它通过 CLI 或者 Node API 传递的所有选项创建出一个 compilation 实例。 它扩展(extends)自 Tapable 类,用来注册和调用插件。 大多数面向用户的插件会首先在 Compiler 上注册,他贯穿了整个webpack的生命周期阶段。

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

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

module.exports = ConsoleLogOnBuildWebpackPlugin;

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

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

三、常用Plugin

HtmlWebpackPlugin

在打包结束后,生成一个html文件,将打包好的js模块引入到该html中

// 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

删除(清理)构建目录

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

mini-css-extract-plugin

提取 CSS 到一个单独的文件中

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'
    }),
    ...
  ]
}

四、自定义Plugin - 测试

//1. webpack加载webpack.config.js配置项,解析到plugins属性使,执行new TestPlugin,执行插件constructor
//2. webpack创建compiler对象(webpack一次执行创建一个)
//3. 遍历所有plugin插件,调用apply方法
//4. 执行剩下编译流程(触发各hook事件)
class TestPlugin {
    constructor() {
        console.log("执行constructor")
    }
    apply(compiler) {
        console.log("执行apply方法");
        debugger;
        // console.log(compiler);
        //tap同步钩子
       
        //environment:在编译器准备环境时调用,时机在配置文件初始化插件之后
        compiler.hooks.environment.tap("TestPlugin", () => {
            console.log("TestPlugin environment");
        })
        //entryOption:entry被处理之后调用
        compiler.hooks.entryOption.tap("TestPlugin", (content,entry) => { 
            console.log("TestPlugin entryOption");
        })
         //-------emit:异步串行--------------------------------- 
        //emit异步钩子同步注册   
        //在资源asset到output之前执行
        compiler.hooks.emit.tap("TestPlugin", (compilation) => {
            console.log("TestPlugin tap异步串行1");
        })
        //tapAsync:异步操作
        compiler.hooks.emit.tapAsync("TestPlugin", (compilation, callback) => {
            setTimeout(() => {
                console.log("TestPlugin tapAsync异步串行2");
                callback();//执行完毕,向下传递
            }, 1000)
        })
        compiler.hooks.emit.tapPromise("TestPlugin", (compilation) => {
            return new Promise((res, rej) => {
                setTimeout(() => {
                    if (true) {
                        res("TestPlugin tapPromise222")
                        console.log("TestPlugin tapPromise异步串行3");
                    } else {
                        rej('promise error');
                    }
                }, 1000)
            })

        })
        //----------------------------------------------
        //-------make:异步并行--------------------------------
        compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
            compilation.hooks.seal.tap("TestPlugin", () => {
                console.log("TestPlugin seal111");
            })
            setTimeout(() => {
                console.log("异步并行: makeAsync111");
                callback();//向下传递
            }, 3000)
        })
        compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
            setTimeout(() => {
                console.log("异步并行: makeAsync222");
                callback();//向下传递
            }, 1000)
        })
        compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
            setTimeout(() => {
                console.log("异步并行: makeAsync333");
                callback();//向下传递
            }, 2000)
        })
        //----------------------------------------------
    }
}

module.exports = TestPlugin;
//webpack.config.js
const TestPlugin = require('./plugin/test-plugin')
module.exports = {
//......
 plugins: [
    new TestPlugin()
 ]
}

异步串行:从上往下依次执行

异步并行:同时执行,谁先执行完谁先输出 

如果想要查看complier和complition对象配置项可以查看以下文章

查看compiler和compliation对象-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值