plugin 的本質 類 (構造函數)
1 重要概念 tapable 類
const {
SyncHook, // 同步 執行
SyncBailHook, // 同步執行,但是一旦有返回值,就執行退出,不再繼續執行其他
AsyncParallelHook, // 異步 並行執行
AsyncSeriesBailHook, // 異步 串行執行
} = require('tapable');
class Lesson {
constructor() {
// 初始化 hook容器
this.hooks = {
// 同步鉤子,任務會依次執行
// go: new SyncHook(['address']),
go: new SyncBailHook(['address']), // 一旦有返回值,就不會再往下執行了
// 異步hooks
// AsyncParallelHook 異步並行
// leave: new AsyncParallelHook(['name', 'age']),
leave: new AsyncSeriesBailHook(['name', 'age']),
};
}
tap() {
// 往hooks 容器中註冊事件/ 添加回調函數
this.hooks.go.tap('class001', (address) => {
console.log('class001', address);
return 111;
});
this.hooks.go.tap('class002', (address) => {
console.log('class002', address);
});
this.hooks.leave.tapAsync('class003', (name, age, cb) => {
setTimeout(() => {
console.log('class003', name, age);
cb();
}, 2000);
});
this.hooks.leave.tapPromise('class004', (name, age) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('class004', name, age);
resolve();
}, 1000);
});
});
}
start() {
this.hooks.go.call('c318');
this.hooks.leave.callAsync('zh', '18', () => {
// 代表所有leave容器中的函數觸發完了,才觸發
console.log('end');
});
}
}
const l = new Lesson();
l.tap();
l.start();
##### 2 complier 類
擁有各種鉤子函數
```js
class Plugin1 {
apply(complier) {
complier.hooks.emit.tap('Plugin1', () => {
console.log('emit 111111111111');
});
complier.hooks.afterEmit.tap('Plugin1', () => {
console.log('emit after 111111111111');
});
}
}
module.exports = Plugin1;
3 compilation 類 (通過compiler.hooks.thisCompilation 獲取),可對文件進行操作
const fs = require('fs');
const util = require('util');
const path = require('path');
const { RawSource } = require('webpack-sources');
// 將fs . readFile 的異步方法,改變成同步的寫法
const readFile = util.promisify(fs.readFile);
class Plugin2 {
apply(compiler) {
// 初始化compilation 的鉤子
compiler.hooks.thisCompilation.tap('Plugin2', (compilation) => {
// debugger;
// console.log(compilation);
compilation.hooks.additionalAssets.tapAsync('Plugin2', async (cb) => {
const content = 'debug';
// 往要輸出資源中,添加一個a.txt
compilation.assets['a.txt'] = {
size() {
return content.length;
}, // 文件大小
source() {
return content;
}, // 文件內容
};
const data = await readFile(path.resolve(__dirname, '../b.txt'));
compilation.assets['b.txt'] = new RawSource(data);
compilation.emitAsset('c.txt', new RawSource(data));
cb();
});
});
}
}
module.exports = Plugin2;
自定義插件 - CopyWebpackPlugin
const path = require('path');
const fs = require('fs');
const {promisify} = require('util')
const { validate } = require('schema-utils');
const globby = require('globby');
const webpack = require('webpack');
const schema = require('./schema.json');
const { Compilation } = require('webpack');
const readFile = promisify(fs.readFile);
const {RawSource} = webpack.sources
class CopyWebpackPlugin {
constructor(options = {}) {
// 驗證options是否符合規範
validate(schema, options, {
name: 'CopyWebpackPlugin'
})
this.options = options;
}
apply(compiler) {
// 初始化compilation
compiler.hooks.thisCompilation.tap('CopyWebpackPlugin', (compilation) => {
// 添加資源的hooks
compilation.hooks.additionalAssets.tapAsync('CopyWebpackPlugin', async (cb) => {
// 將from中的資源複製到to中,輸出出去
const { from, ignore } = this.options;
const to = this.options.to ? this.options.to : '.';
// context就是webpack配置
// 運行指令的目錄
const context = compiler.options.context; // process.cwd()
// 將輸入路徑變成絕對路徑
const absoluteFrom = path.isAbsolute(from) ? from : path.resolve(context, from);
// 1. 過濾掉ignore的文件
// globby(要處理的文件夾,options)
const paths = await globby(absoluteFrom, { ignore });
console.log(paths); // 所有要加載的文件路徑數組
// 2. 讀取paths中所有資源
const files = await Promise.all(
paths.map(async (absolutePath) => {
// 讀取文件
const data = await readFile(absolutePath);
// basename得到最後的文件名稱
const relativePath = path.basename(absolutePath);
// 和to屬性結合
// 沒有to --> reset.css
// 有to --> css/reset.css
const filename = path.join(to, relativePath);
return {
// 文件數據
data,
// 文件名稱
filename
}
})
)
// 3. 生成webpack格式的資源
const assets = files.map((file) => {
const source = new RawSource(file.data);
return {
source,
filename: file.filename
}
})
// 4. 添加compilation中,輸出出去
assets.forEach((asset) => {
compilation.emitAsset(asset.filename, asset.source);
})
cb();
})
})
}
}
module.exports = CopyWebpackPlugin;