在之前的文章中,我们已经手写了webpack的打包过程以及loader处理非js文件的过程,接下来就是plugin(插件)了。 plugin作用在webpack编译的各个阶段,通过在不同阶段webpack的compiler hook里面进行进行相应的操作来改变webpack的某些行为。具体的hook函数以及编写Plugin插件的方法可以参照官网 webpack.docschina.org/api/compile… webpack.docschina.org/api/plugins… webpack.docschina.org/contribute/…
1 plugin工作流程
tapable工具为webpack提供了插件接口,向外暴露了tap,tapAsync 和 tapPromise 等方法,插件可以使用这些方法向webpack中注入自定义的构建步骤,这些步骤将在构建过程中被触发。我们可以借助tapable来实现我们的自定义的插件。
tapable的流程类似于发布-订阅的模式,首注册,后调用,具体例子可以在www.npmjs.com/package/tap… 里看到。
2 编写一个plugin
参照官网的规范,我们创建一个修改文件打包后输出文件名为一个随机hash值的plugin(举例用的,复杂的后面再更),在之前的代码中,我们的输出文件名一直都是bundle.js,这次改成一个随机的hash值命名,比如769601666.js
2.1 plugin内容
根据官网规范,plugin是一个class,并且里面有一个apply函数,我们创建一个文件ChangeOutputPath.js
export class ChangeOutputPath{
apply(hooks){
hooks.emitFile.tap("changeOut",(context)=>{
context.ChangeOutputPath("./dist/"+hashCode("bundle")+".js")
})
}
}
function hashCode(str) {
var h = 0;
var len = str.length;
var t = 2147483648;
for (var i = 0; i < len; i++) {
h = 31 * h + str.charCodeAt(i);
if (h > 2147483647) h %= t;
}
return h;
}
在index.js里面写入
import {ChangeOutputPath} from "../webpackSource/ChangeOutputPath.js"
import {SyncHook} from "tapable"
const webpackConfig = {
...
plugins:[new ChangeOutputPath()]
}
const hooks = {
emitFile: new SyncHook(["context"])
}
// 注册函数
function initPlugins(){
const plugins = webpackConfig.plugins
plugins.forEach((plugin)=>{
plugin.apply(hooks)
})
}
function build(graph){
...
let outputPath = "./dist/bundle.js"
// 调用
const context = {
ChangeOutputPath(path){
outputPath = path
}
}
hooks.emitFile.call(context)
fs.writeFileSync(outputPath,code1)
}
initPlugins()
const graph = createGraph()
build(graph)