Webpack 核心双引擎:Loader 与 Plugin 详解

我们知道,Webpack 本质是 "模块化打包工具",但它有个 "天生短板":默认只认识 JS 和 JSON 文件。可实际开发中,我们要处理的文件远不止这些 ------ 写样式要用到 CSS、Less,插入图片要用到 PNG、SVG,甚至还会用 TypeScript 写代码、用 Vue/React 写组件。这些 "非 JS/JSON 文件",Webpack 自己处理不了;而且,除了 "处理文件",我们还需要做很多 "额外操作":比如代码压缩、自动生成 HTML、清除旧打包文件...... 这些需求,也超出了 Webpack 本身的基础能力。

  • Loader 负责 "补全 Webpack 的文件处理能力"------ 帮它看懂 CSS、图片、TS 这些 "陌生文件",把它们转换成 Webpack 能理解的模块;

  • Plugin 负责 "扩展 Webpack 的额外功能"------ 从打包前的代码检查,到打包中的资源优化,再到打包后的文件清理,覆盖整个构建流程的 "增值需求"。

可以说,正是有了 Loader 和 Plugin 的配合,Webpack 才从一个 "基础打包工具",变成了能适配各种开发场景的 "前端工程化核心"。接下来,我们就分别拆解这两个 "引擎" 的作用、原理和使用逻辑,搞懂它们如何让 Webpack 真正 "好用"。

Loader

loader本质上是一个函数,它的作用是将某个 源码 字符串转换成另一个源码字符串返回。

loader函数的将在模块解析的过程中被调用,以得到最终的源码。

处理loaders流程:

比如: 我们在配置中,配置了一个规则,然后一个规则上,使用了4个loader;

运行过程时:首先匹配规则,满足的时候"读取规则中的对应Loaders数组"

Loaders 数组从尾往前运行--》loader4 loader3 loader2 loader1

loader 配置

完整配置

js 复制代码
module.exports = {
    module: { //针对模块的配置,目前版本只有两个配置,rules、noParse
        rules: [ //模块匹配规则,可以存在多个规则
            { //每个规则是一个对象
                test: /.js$/, //匹配的模块正则
                use: [ //匹配到后应用的规则模块
                    {  //其中一个规则
                        loader: "模块路径", //loader模块的路径,该字符串会被放置到require中
                        options: { //向对应loader传递的额外参数

                        }
                    }
                ]
            }
        ]
    }
}

简化配置

js 复制代码
module.exports = {
    module: { //针对模块的配置,目前版本只有两个配置,rules、noParse
        rules: [ //模块匹配规则,可以存在多个规则
            { //每个规则是一个对象
                test: /.js$/, //匹配的模块正则
                use: ["模块路径1", "模块路径2"]//loader模块的路径,该字符串会被放置到require中
            }
        ]
    }
}

Plugin

loader的功能定位是转换代码,而一些其他的操作难以使用Plugin完成,比如:

  • 当webpack生成文件时,顺便多生成一个说明描述文件
  • 当webpack编译启动时,控制台输出一句话表示webpack启动了
  • .....

这种类似的功能需要把功能嵌入到webpack的编译流程中,而这种事情的实现是依托于plugin的

webpack,在编译整个过程中,在关键点触发钩子函数(HOOKS),我们监听他并且处理其他事情的函数是plugin。

"监听钩子 + 执行逻辑" 是 Plugin 的唯一工作方式

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

JavaScript 复制代码
var plugin = {
    apply: function(compiler){
        
    }
}

通常,习惯上,我们会将该对象写成构造函数的模式

JavaScript 复制代码
class MyPlugin{
    apply(compiler){

    }
}

var plugin = new MyPlugin();

要将插件应用到webpack,需要把插件对象配置到webpack的plugins数组中,如下:

JavaScript 复制代码
module.exports = {
    plugins:[
        new MyPlugin()
    ]
}

apply函数会在初始化阶段,创建好Compiler对象后运行。

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

apply方法会在创建好compiler对象后调用,并向方法传入一个compiler对象

compiler对象提供了大量的钩子函数(hooks,可以理解为事件),plugin的开发者可以注册这些钩子函数,参与webpack编译和生成。

你可以在apply方法中使用下面的代码注册钩子函数:

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

事件名称

即要监听的事件名,即钩子名,所有的钩子:www.webpackjs.com/api/compile...

事件类型

这一部分使用的是 Tapable API,这个小型的库是一个专门用于钩子函数监听的库。

它提供了一些事件类型:

  • tap:注册一个同步的钩子函数,函数运行完毕则表示事件处理结束
  • tapAsync:注册一个基于回调的异步的钩子函数,函数通过调用一个回调表示事件处理结束
  • tapPromise:注册一个基于Promise的异步的钩子函数,函数通过返回的Promise进入已决状态表示事件处理结束

处理函数

处理函数有一个事件参数compilation

上期知识点

深入理解:Webpack编译原理

你知道Webpack解决的问题是什么嘛?

相关推荐
weixin_382395235 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__5 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.6 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~7 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华7 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子10 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅10 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni10 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学11 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端