前言

通过前面的学习,主要了解了webpack的配置和运行机制。今天这篇文章主要是来记录对plugin的学习。

插件

插件的功能的话,我们就来写一个打包时去除所有log的功能。首先,从webpack中文网中我们可以知道,插件是一个有apply属性的js对象。这个apply对象会被webpack的compiler对象调用。如下所示:

1
2
3
4
5
6
class CleanLogPlugin{

apply(compiler){

}
}

那么首先,我们得绑定compiler中的一个钩子,在上一章我们知道,打完包输出的钩子函数是emit,这里我们绑定emit钩子函数来实现我们的逻辑。

1
2
3
4
5
6
7
8
9
10
class CleanLogPlugin{

apply(compiler){
compiler.hooks.emit.tapAsync('cleanLogPlugin',(compilation, callback) => {
// compilation中可以访问所有的构建编译的资源
console.log(compilation);
callback();
})
}
}

然后我们可以解读出compilation对象的数据,再通过assets来获取我们需要的内容

1
2
3
4
5
6
7
// 这里是webpack源码中Compilation对asset的定义和说明。
/**
* @typedef {Object} Asset
* @property {string} name the filename of the asset
* @property {Source} source source of the asset
* @property {AssetInfo} info info about the asset
*/

因为打包输出的内容肯定不止我们的js文件,所以这里我们需要拿到所有的js文件,然后循环对所有js文件内容做替换。

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
class CleanLogPlugin{

apply(compiler){
compiler.hooks.emit.tapAsync('cleanLogPlugin',(compilation, callback) => {
// 找出所有的js文件
let jsFilesNameList = Object.keys(compilation.assets).filter(filename => filename.indexOf('.js') > -1);

let reg = /console\.log\(\b.*\)/g;

for(let filename of jsFilesNameList){
// 获取文件内容
let fileContent = compilation.assets[filename].source();
fileContent = fileContent.replace(reg, '');
// 重写assets内对应js文件的source和size方法
compilation.assets[filename] = {
source: () => {
return fileContent
},
size: () => {
return Buffer.byteLength(fileContent, 'utf8')
}
}
}

callback();
})
}
}

总结

其实并没有什么特别想说明的,之后的话,平时可以多去看一些webpack插件源码并尝试自己手动实现它。然后去和别人的做一下对比。学习别人是如何把一个插件写好。