前言:笔者把学习的webpack知识从基础到原理写个系列,以便回顾。希望能帮助到更多正在学习webpack的小伙伴。
前言:plugin只能在webpack里面运行
插件的基本结构
// 基本结构
class MyPlugin {
apply(compiler){
compiler.hooks.done.tap('My Plugin',(
// 插件的hooks
) => {
// 插件处理逻辑
})
}
}
module.exports = MyPlugin
// 插件使用:
plugins: [new MyPlugin()]
下面通过一个例子看下:
- 1.编写简单的一个plugins
// plugins/my-plugin.js module.exports = class MyPlugin { constructor(options) { this.options = options; }
apply(compiler) { console.log('my plugin is done'); console.log('compiler', this.options); } };
+ 2.在webpack中引入MyPlugin
```js
// webpack.config.js
const path = require('path');
const MyPlugin = require('./plugins/my-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js',
},
mode: 'production',
plugins: [
new MyPlugin({
name: 'curry',
}),
],
};
- 3.运行 npm run build 打印结果
下面看下复杂的插件场景:
插件中如何获取传递的参数?
- 通过插件的构造函数获取
module.exports = class MyPlugin { constructor(options){ this.options = options; }
apply(){ console.log('apply', this.options) } }
#### 插件的错误处理?
+ 1.参数校验阶段可以直接 throw 方式抛出
```js
throw new Error('error message')
2.通过 compilation 对象的 warnings 和 errors 接收
compilation.warnings.push('warning') compilation.errors.push('erros')
如何进行文件读写
通过 compilation进行文件读写,文件写入需要webpack-sources
const { RawSources } = require('webpack-sources') module.exports = class MyPlugin { constructor(options){ this.options = options; } apply(compiler){ const { name } = this.options; compiler.hooks('emit', (compilation, cb) => { compilation.assets[name] = new RawSources('demo') cb() }) } }
下面进行以下实战:编写一个压缩构建资源为zip包的插件
要求:
- 1.生成的zip包文件名称可以通过插件传入
- 2.需要使用compiler对象上的特地hooks进行资源的生成
准备知识:nodejs里面将文件压缩为zip包
- 使用:jszip https://www.npmjs.com/package/jszip
- 使用示例:
var zip = new JSZip();
zip.file("Hello.txt", "Hello World\n");
var img = zip.folder("images"); img.file("smile.gif", imgData, {base64: true});
zip.generateAsync({type:"blob"}).then(function(content) { // see FileSaver.js saveAs(content, "example.zip"); });
#### 文件生成:需要使用emit
+ Compiler 上负责文件生成的hooks是emit ,一个异步的hook
+ emit 生成文件阶段,读取的是compilation.assets 对象的值,可以将zip资源包设置到compilation.assets 对象上
### 开始编写:
#### 配置webpack
```js
// webpack.config.js
const path = require('path');
const ZipPlugin = require('./plugins/zip-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js',
},
mode: 'production',
plugins: [
new ZipPlugin({
filename: 'offline',
}),
],
};
编写zip-plugin
// plugins/zip-plugin.js
const JSZip = require('jszip');
const path = require('path');
const { RawSource } = require('webpack-sources');
const zip = new JSZip();
module.exports = class ZipPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
compiler.hooks.emit.tapAsync('ZipPlugin', (compilation, callback) => {
const folder = zip.folder(this.options.filename);
for (let filename in compilation.assets) {
const source = compilation.assets[filename].source();
folder.file(filename, source);
}
zip
.generateAsync({
type: 'nodebuffer',
})
.then(content => {
const outpath = path.join(compilation.options.output.path, `${this.options.filename}.zip`);
const outputRelativePath = path.relative(compilation.options.output.path, outpath);
compilation.assets[outputRelativePath] = new RawSource(content);
callback();
});
});
}
};