从0-1webpack打包——手写实现webpack(3)

75 阅读1分钟

在之前的文章中,我们已经手写了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提供了插件接口,向外暴露了taptapAsync 和 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)