Webpack——了解plugin的结构及其应用

📚上篇文章分析了loader的运行过程。loader的功能定位是进行预处理转换代码,而另外一些操作需要依靠plugin来完成。先看plugins在官网中的定义Plugins | webpack

Plugins are the backbone of webpack. Webpack itself is built on the same plugin system that you use in your webpack configuration!

They also serve the purpose of doing anything else that a loader cannot do. Webpack provides many such plugins out of the box.

老规矩,提炼一下意思,大致就是说plugins很重要;可以完成loaders无法完成的事

具体是什么事呢?举个例子: 当webpack生成文件时,顺便多生成一个说明描述文件。

这种操作其实就是通过plugin,把某些功能嵌入到webpack的编译流程中。

用之前的webpack编译过程图来看:

plugin可以认为是注册事件的,上图的点是一些事件触发点(实际上的数量多得多),在这些节点可能会触发事件,而plugin可以监听这些事件

1. plugins的结构

随便找一个plugin看看

plugin的本质是一个带有apply方法的对象。

js 复制代码
class ConsoleLogOnBuildWebpackPlugin {
  apply(compiler) {
  
  }
}
module.exports = ConsoleLogOnBuildWebpackPlugin;

apply方法会在该plugin被使用时调用,具体是什么时候呢?

apply的参数compiler(编译器)是一个对象:

  • compiler对象是在初始化阶段构建的
  • 整个webpack打包期间只有一个compiler对象
  • 后续完成打包工作的是compiler对象内部创建的compilation

可以看到,当文件发生变化时,是从编译重新开始的,需要重新创建compilation,但不需要重新创建compiler。

apply方法会在初始化阶段创建好compiler对象后调用,并向方法传入一个compiler对象。

这样来看,apply方法只调用一次,但既然plugins能监听各种事件,是怎么监听的呢?

其实,apply方法是用来注册事件的:

js 复制代码
class MyPlugin{
    // 
    apply(compiler){ 
        compiler.hooks.事件名称.事件类型(name, function(compilation){
            //事件处理函数
        })
    }
}

compiler对象提供了大量的钩子函数: Compiler Hooks | webpack

😮可以根据文档自己写一个plugin玩玩,不过在实际开发中,大部分情况下只需要会使用就可以了

2. 使用

把插件对象配置到webpack的plugins数组中:

js 复制代码
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 访问内置插件

module.exports = {
    //...
    plugins:[
        new webpack.ProgressPlugin(),
        new HtmlWebpackPlugin({ template: './src/index.html' }),
    ]
}

3. 下面是一些常用plugin的使用示例

www.npmjs.com/

🌟clean-webpack-plugin

  • 清除输出目录

🌟html-webpack-plugin

  • 自动生成页面

使用场景:每次打包都要在dist目录手写html页面并引入js太麻烦

使用示例:

js 复制代码
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    // ...
    entry: { // 多个入口 每个对应一个js
        home: "./src/index.js",
        a: "./src/a.js"
    },
    //...
    plugins: [
        //...
        // 两个页面,用不同的chunk
        new HtmlWebpackPlugin({
            template: "./public/index.html", // 生成main.js页面使用的模板
            filename: "home.html",
            chunks: ["home"]  // 使用的js是哪个chunk的js 
        }),// chunks默认为"all"表示每个js都使用
        new HtmlWebpackPlugin({
            template: "./public/index.html",
            filename: "a.html",
            chunks: ["a"]
        })
    ]
}

🌟copy-webpack-plugin

  • 复制静态资源

使用场景:如果静态资源不是通过在js文件中引入来使用的(比如html),因为这个静态资源的引入无法像js文件一样被解析,导致打包后找不到该静态资源。所以需要把原本的静态资源目录复制到dist目录里

js 复制代码
// 传入复制规则
new CopyPlugin([
    { from: "./public", to: "./" } // to相对的是输出目录
])

如果输出目录已经存在要复制的某个文件,会自动不再复制这个文件

🌟 mini-css-extract-plugin

  • 抽离css生成css文件

该库提供了1个plugin和1个loader:

  1. plugin:负责生成css文件
  2. loader:负责记录要生成的css文件的内容,同时导出开启css-module后的样式对象

使用方式:

js 复制代码
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader?modules"]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin() //负责生成css文件
    ]
}

webpack内置plugin

webpack.js.org/plugins/def...

内置plugin的使用:

js 复制代码
const webpack = require('webpack'); // 访问内置插件

module.exports = {
    //...
    plugins:[
        // new webpack.ProgressPlugin(),
        // 可以配置生成的文件名,类似于output.filename
        new MiniCssExtractPlugin({
            filename: "css/[name].[contenthash:5].css"
        })
    ]
}

🌟 ProvidePlugin

自动加载模块

js 复制代码
new webpack.ProvidePlugin({
  $: 'jquery',
  _: 'lodash'
})

使用:

js 复制代码
// import $ from 'jquery'; 不再需要import,可直接使用
// import _ from 'lodash';
$('body').append('<h1>Hello, webpack!</h1>');
const sum = _.sum( [1, 2, 3, 4, 5]); // 输出: 15

🌟 DefinePlugin

定义全局常量

js 复制代码
new webpack.DefinePlugin({
  VERSION: `"1.0.0"`, // VERSION = "1.0.0"
  TWO: '1+1', // VERSION = "1+1"
});

这样配置后,写代码时,可以直接使用插件中提供的常量,当webpack编译完成后,会自动替换为常量的值

使用:

js 复制代码
console.log('Running App version ' + VERSION); 
// 输出 Running App version 1.0.0
相关推荐
满分观察网友z8 分钟前
一行代码,干掉我 10 行!聊聊 filter(Boolean) 这个让我又爱又恨的小恶魔
前端
白总Server8 分钟前
Web 架构之 GraphQL 与 REST API 对比与选型
java·大数据·前端·javascript·后端·架构·graphql
holidaypenguin13 分钟前
React 将任意 ReactNode 类型的节点在render函数外渲染到页面上
前端·react.js
咸虾米14 分钟前
css布局排序order的用法,可使flex和grid布局轻松调整顺序
前端·css
袁煦丞18 分钟前
AI配音情感魔术师ChatTTS: cpolar内网穿透实验室第414个成功挑战
前端·程序员·远程工作
Mintopia25 分钟前
Three.js 的魔法手势:让 3D 世界在指尖起舞
前端·javascript·three.js
wordbaby26 分钟前
别再混淆了!一文看懂 useNavigate 和 redirect 的适用场景
前端·react.js
Hilaku28 分钟前
Vue 项目不要再用 Pinia 了,组合式 API + ref() 才是王道
前端·javascript·vue.js
我想说一句31 分钟前
伪元素魔法:让CSS变身"无中生有"的魔术师
前端·javascript
_一两风31 分钟前
如何DIY一个独特的表情?居然如此简单!
前端·人工智能·产品