webpack开发插件实战:

204 阅读2分钟

plugin介绍:

通过插件可以扩展webpack,加入自定义的构建行为,使webpack可以执行更广泛的任务,有更强的构建能力

plugin工作原理:

  • webpack就像一条生产线,这条生产线有很多流程,插件就像一个插入到生产线的一个功能,在特定时机对生产线上的资源做处理。webpack通过tapable来组织复杂的生产线,插件只需监听它所关心的事件,就能加入到生产线中,去改变生产线的运作。
  • 通俗来讲,就是webpack在编译代码过程中,会触发一系列tapable钩子事件,插件所做的,就是找到相应钩子,往上面挂上自己的任务,也就是注册事件。这样,当webpack构建的时候,插件注册的事件就会随着钩子的触发而执行了。

理解tapable:

image.png

webpack内部的钩子

  • 钩子的本质是事件,tapable为webpack提供了统一的插件接口(钩子)类型定义,它是webpack的核心功能库,webpack中目前有十种钩子

image.png

tapable统一暴露了三个方法给插件

用于注入不同类型的自定义构建行为:

1.  tap:可以注册同步钩子和异步钩子
1.  tapAsync:回调方式注册异步钩子
1.  tapPromise:Promise方式注册异步钩子

plugin构建对象-compiler和compilation:

  • compiler的介绍:compiler对象贯穿了整个webpack生命周期的一个实例,从启动到结束都存在,它代表了完整的webpack环境配置
  • compilation:该对象是在每次新的资源构建时创建的一个实例,它代表了一次单独的版本构建。比如在开发模式下,启用watch后,每次文件都会触发新的compilation,从而生成一组新的编译资源。

webpack在加载和执行插件时的核心流程:

暂时无法在飞书文档外展示此内容

怎么用node调试compiler和compilation:

  • 为什么需要node调试工具:

在webpack插件开发中,直接调试compiler和compilation对象是理解其内部机制的关键

  • 调试的流程:

    • 在debugger行设置断点
    • 启动webpack调试:node --inspect-brk ./node_modules/webpack/bin/webpack.js
    • 调试后,找到需要的属性,在控制台打印测试

自定义插件

//需求:给打包输出文件添加注释

const { compilation } = require("webpack");

//开发思路:
//触发时机:生成资源到输出目录之前 emit钩子
//如何获取打包输出的资源?compilation可以获取所有的即将输出的资源文件

class BannerWebpackPlugin{
    constructor(){}
    apply(compiler){
        compiler.hooks.emit.tap('BannerWebpackPlugin',(compilation)=>{
            debugger;
            const extensions=['css','js'];
            //过滤只保留这两种文件
            const assets=Object.keys(compilation.assets).filter((assetpath)=>{
                const splitted=assetpath.split('.');
                const extension=splitted[splitted.length-1];
                return extensions.includes(extension)
            })
            const prefix = '/* Built by BannerWebpackPlugin */\n';
            assets.forEach((asset)=>{
                const source=compilation.assets[asset].source();//原来内容
                const content=prefix+source; //拼接上注释
                //修改资源
                compilation.assets[asset]={
                    source(){
                        return content; //资源内容
                    },
                    size(){
                        return content.length
                    }
                }
            })
        })
    }
}

module.exports=BannerWebpackPlugin