如今项目大部分都使用webpack 进行编译,一方面 webpack 生命力比较旺盛,另外一方面 webpack 的生态很是完善。咱们90%的场景都可以知足。但有时候也会遇到一些特定的业务场景,好比有时候会遇到须要对编译后的文件进行一些文件注入 等其余特定化的需求。怎么办呢?那就来写一个业务定制化的webpack 插件吧。webpack
官方文档可见: https://webpack.js.org/contribute/writing-a-plugin/#creating-a-pluginweb
首先咱们了解下一个插件的主要结构api
class DtoolPlugin { // 构造函数,进行参数校验等功能 constructor(args) {} // 定义插件执行的方法体,主要逻辑都在这里完成,webpack 会自动调用此方法 apply(compiler) {} }
下面咱们来看下 compiler 这个关键对象,compile 提供了 webpack 一系列操做的钩子函数,下面说一说经常使用的hooksapp
官方文档可见:https://webpack.js.org/api/compiler-hooks/#watching异步
下面以真实案例来说解async
apply(compiler) { const metaParams = this.metaParams; const tester = {test: this.test}; compiler.hooks.compilation.tap('DtoolPlugin', (compilation) => { compilation.hooks.optimizeChunkAssets.tapAsync('DtoolPlugin', (chunks, done) => { wrapChunks(compilation, chunks); done(); }) }); // 注入文件方法 function wrapChunks(compilation, chunks) { chunks.forEach(chunk => { const args = { hash: compilation.hash, chunkhash: chunk.hash }; chunk.files.forEach(fileName => { if (ModuleFilenameHelpers.matchObject(tester, fileName)) { const content = 'xxxxx'; // 注入内容 // assets 对象是编译后的对象,以文件名为key , 值为文件内容 、 文件size 等一系列信息, 经过asset 能够对文件名字 , 文件内容作变动 compilation.assets[fileName] = new ConcatSource( compilation.assets[fileName], String(content), ); } }); }); } }
hooks 调用的时候有个类型 plugin types 支持 tap , 有些支持异步类型 tapAsync tapPromise函数
compiler.hooks.run.tapAsync('MyPlugin', (source, target, routesList, callback) => { console.log('Asynchronously tapping the run hook.'); callback(); }); compiler.hooks.run.tapPromise('MyPlugin', (source, target, routesList) => { return new Promise(resolve => setTimeout(resolve, 1000)).then(() => { console.log('Asynchronously tapping the run hook with a delay.'); }); }); compiler.hooks.run.tapPromise('MyPlugin', async (source, target, routesList) => { await new Promise(resolve => setTimeout(resolve, 1000)); console.log('Asynchronously tapping the run hook with a delay.'); });