Plugin
由于 loader 作用范围是很明显的,所以就有了它的边界,那么超出这个边界的事情我们就可以使用 Plugin 去实现,这样 webpack 就可以适用用各种各样的场景,如 loader 很困难直接对多种规则的内容进行最后的整合然后输出,而且 loader 之间有顺序规则之类,如果规则与规则之间有关联且要按某种顺序进行执行,那么就很难实现,而这是使用 Plugin 实现是最好的。
Webpack 通过 Plugin 机制让其更加灵活,以适应各种应用场景。
一旦我们打开了 webpack 编译器和每个单独编译的大门,我们可以使用引擎做的事情是无限可能的。我们可以重新格式化存在的文件、创建派生文件、完全伪造一个新文件。
编一个 Plugin
TestPlugin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class TestPlugin { constructor(doneCallback, failCallback) { this.doneCallback = doneCallback; this.failCallback = failCallback; } apply(compiler) { compiler.hooks.emit.tapAsync("生成md", (compilation, callback) => { var filelist = "构成生成的文件:\n\n"; for (var filename in compilation.assets) { filelist += "- " + filename + "\n"; }
compilation.assets["filelist.md"] = { source: function () { return filelist; }, size: function () { return filelist.length; }, };
callback(); }); compiler.hooks.done.tap("完成成功", (stats) => { this.doneCallback(stats); }); compiler.hooks.failed.tap("完成失败", (err) => { this.failCallback(err); }); } }
module.exports = TestPlugin;
|
webpack.config.js
1 2 3 4 5 6 7 8 9 10
| plugins: [ new TestPlugin( (p) => { console.log("w完成-", p); }, () => { console.log("w失败-", p); } ), ],
|
Webpack 启动后,在读取配置的过程中会先执行 new TestPlugin(options) 初始化一个 TestPlugin 获得其实例。
在初始化 compiler 对象后,再调用 TestPlugin.apply(compiler) 给插件实例传入 compiler 对象。
插件实例在获取到 compiler 对象后,就可以通过 compiler.plugin(事件名称, 回调函数) 监听到 Webpack 广播出来的事件。
并且可以通过 compiler 对象去操作 Webpack。
但 Compiler 和 Compilation 都继承自 Tapable,所以我们可以使用 compilation.hooks.someHook.tap(…)等监听到广播出来的事件。
但 apply 与 plugin 自定义比较简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| /** * 广播出事件 * event-name 为事件名称,注意不要和现有的事件重名 * params 为附带的参数 */ compiler.apply('event-name',params);
/** * 监听名称为 event-name 的事件,当 event-name 事件发生时,函数就会被执行。 * 同时函数中的 params 参数为广播事件时附带的参数。 */ compiler.plugin('event-name',function(params) {
});
|
调试
不管是 npm 还是 webpack 都是基于 nodejs 的工具。所以最终是调试 node。
npm 方式调试
package.json 文件 scripts 项中添加一个 key 为 debug 的配置,内容如下
1 2 3
| "scripts": { "debug": "node --inspect-brk=5858 ./node_modules/webpack/bin/webpack" }
|
vscode Ctrl+shift+D
切换为调试,选择Add Configuration
。vscode 会自动生成一个 launch.json 文件,将文件的内容调整为以下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "build", "stopOnEntry": false, "runtimeExecutable": "npm", "runtimeArgs": ["run", "debug"], "port": 5858 } ] }
|
runtimeExecutable 要运行的 shell,runtimeArgs shell 运行时需要的的参数,这个类似 Node.js 的 child_process 模块的 spawn。
其中端口 port 配置需要和 inspect-brk 配置的端口保持一致。stopOnEntry 为 true 表示在运行的第一行代码中添加断点,点击开始调试按钮,即可进入如下界面
然后我们就可以在代码的行数上点击出现小红点,就为打上断点了。
运行 node 调试
由于上面的调试方式需要在 package 里配置,program 将要进行调试的程序的路径,但 program 可以把运行路径写入,那么就可以直接触发 webpack 而进入调试,不用在项目加入任何配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "webpack", "stopOnEntry": false, "program": "${workspaceFolder}/node_modules/webpack/bin/webpack" } ] }
|
当然我们还可以把调试放到 chrome 里,这个就不在这里配置了。
所谓的调试都是在 node 上进行了,而已都需要 --inspect-brk
开启出一个调试服务。
一些常用配置说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| { // 配置名称,将会在启动配置的下拉菜单中显示 "name": "C++ Launch (GDB)", // 配置类型,这里只能为cppdbg "type": "cppdbg", // 请求配置类型,可以为launch(启动)或attach(附加) "request": "launch", // 调试器启动类型,这里只能为Local "launchOptionType": "Local", // 生成目标架构,一般为x86或x64, // 可以为x86, arm, arm64, mips, x64, amd64, x86_64 "targetArchitecture": "x86", // 将要进行调试的程序的路径 "program": "${workspaceRoot}", // miDebugger的路径,注意这里要与MinGw的路径对应 "miDebuggerPath":"D:\\mingw\\bin\\gdb.exe", // 程序调试时传递给程序的命令行参数,一般设为空即可 "args": [], // 设为true时程序将暂停在程序入口处,一般设置为false "stopAtEntry": false, // 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录 "cwd": "${workspaceRoot}", // 调试时是否显示控制台窗口,一般设置为true显示控制台 "externalConsole": true, // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc "preLaunchTask": "g++" //传递给运行时可执行文件的可选参数。 "runtimeArgs":[]
}
|
1 2 3 4 5 6 7 8 9 10 11
| ${workspaceRoot} VS Code当前打开的文件夹
${file} 当前打开的文件
${relativeFile} 相对于workspaceRoot的相对路径
${fileBasename} 当前打开文件的文件名
${fileDirname} 所在的文件夹,是绝对路径
${fileExtname} 当前打开文件的拓展名,如.json
|
资料
这篇资料讲的很详细,上面就不进行详细了。
Webpack 原理-编写 Plugin
如何开发一个 plugin 例子
以下都是钩子的 API,不懂的可以进行查询
webpack 官网-Tapable
webpack 官网-compiler API
webpack 官网-compilation API
以下都是 vscode 调试相关的,比如怎么调试 webpack 插件或 loader
vscode 调试 webpack
vscode 中 launch.json 部分配置项解释
VS Code 调试
最后更新时间: