Webpack 插件概念
在 Webpack 构建流程中的各个阶段、特定时机中劫持做一些代码处理、注入扩展逻辑来改变构建结果或做你想要的事情。
Webpack 插件基本架构
插件由一个构造函数实例化出来。构造函数定义 apply 方法,在安装插件时,apply 方法会被 Webpack compiler 调用一次。apply 方法可以接收一个 Webpack compiler 对象的引用
1class HelloWorldPlugin {2 apply(compiler) {3 compiler.hooks.done.tap(4 "Hello World Plugin",5 (stats /* 在 hook 被触及时,会将 stats 作为参数传入。 */) => {6 console.log("Hello World!");7 }8 );9 }10}11module.exports = HelloWorldPlugin;
使用插件
1// webpack.config.js2var HelloWorldPlugin = require("hello-world");34module.exports = {5 // ... 这里是其他配置 ...6 plugins: [new HelloWorldPlugin({ options: true })],7};
compiler 编译器
这个对象包含了 webpack 环境所有的的配置信息,包含 options,loaders,plugins 这些信息,这个对象在 webpack 启动时候被实例化,它是全局唯一的,可以简单地把它理解为 webpack 实例。
hook 生命周期钩子
compiler 暴露了一些钩子
https://webpack.js.org/api/compiler-hooks/#environment
常用的钩子
1beforeRun // compiler.run() 之前处理逻辑2run //在开始读取记录之前3beforeCompile //创建编译参数后执行插件4compile //在创建新编译之前立即调用5make //在完成编译之前执行6afterCompile //在完成编译之后执行7entryOption //在 webpack 选项中的 entry 配置项处理过之后8...
同步钩子的种类
- SyncHook(同步钩子) - SyncHook
- Bail Hooks(保释钩子) - SyncBailHook
- Waterfall Hooks(瀑布钩子) - SyncWaterfallHook
异步钩子的种类
- Async Series Hook(异步串行钩子) - AsyncSeriesHook
- Async waterfall(异步瀑布钩子) - AsyncWaterfallHook
- Async Series Bail - AsyncSeriesBailHook
- Async Parallel - AsyncParallelHook
- Async Series Bail - AsyncSeriesBailHook
compilation 子编译器
compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。
当 webpack 以开发模式运行时,每当检测到一个文件变化,一次新的 compilation 将被创建。
compilation 对象也提供了很多事件回调供插件做扩展。
通过 compilation 也能读取到 compiler 对象
compiler 和 compilation 区别
compiler代表了整个 webpack 从启动到关闭的生命周期,而 compilation 只代表一次单独的编译。 compilation 是 SyncHook 同步钩子
tap
对不同钩子进行 tap 处理即可,其中 tap 方法用于同步处理,异步方式则可以调用 tapAsync 方法或 tapPromise 方法。
1// tapAsync2class HelloAsyncPlugin {3 apply(compiler) {4 compiler.hooks.emit.tapAsync(5 'HelloAsyncPlugin',6 (compilation, callback) => {7 // Do something async...8 setTimeout(function () {9 console.log('Done with async work...');10 callback();11 }, 1000);12 }13 );14 }15}1617module.exports = HelloAsyncPlugin;
1//tapPromise2class HelloAsyncPlugin {3 apply(compiler) {4 compiler.hooks.emit.tapPromise('HelloAsyncPlugin', (compilation) => {5 // return a Promise that resolves when we are done...6 return new Promise((resolve, reject) => {7 setTimeout(function () {8 console.log('Done with async work...');9 resolve();10 }, 1000);11 });12 });13 }14}1516module.exports = HelloAsyncPlugin;
我开发的输出一个编译文件列表MarkDown的插件
1const pluginName = 'FileList';23class FileListPlugin {4 apply(compiler) {5 compiler.hooks.emit.tap(pluginName, (compilation) => {6 var filelist = '生成的文件:\n\n';7 for (var filename in compilation.assets) {8 filelist += '- ' + filename + '\n';9 }10 compilation.assets['filelist.md'] = {11 source: function () {12 return filelist;13 },14 size: function () {15 return filelist.length;16 },17 };18 });19 }20}2122module.exports = FileListPlugin;
至此,我们就开发了一个简单的webpack插件