webpack的自定义插件学习

Plugin

webpack的插件可以加入自定义构建的行为,使webpack更加灵活的执行更广泛的任务

webpack在编译源码的过程中,会触发一系列的Tapable钩子事件,而插件就找到合适时机的钩子事件,向其挂载自己的任务,这样就会在webpack构建的时候随着钩子触发而执行

webpack生命周期两个核心对象compiler和compilation

Compiler 模块是 webpack 的主要引擎,它通过 CLI 或者 Node API 传递的所有选项创建出一个 compilation 实例。 它扩展(extends)自 Tapable 类,用来注册和调用插件。 大多数面向用户的插件会首先在 Compiler 上注册。

compiler的一些属性
compiler.options 可以访问本次启动 webpack 时候所有的配置文件,包括但不限于 loaders 、 entry 、 output 、 plugin 等等完整配置信息。
compiler.inputFileSystem 和 compiler.outputFileSystem 可以进行文件操作,相当于 Nodejs 中 fs。
compiler.hooks 可以注册 tapable 的不同种类 Hook,从而可以在 compiler 生命周期中植入不同的逻辑。
compilation 对象

compilation 对象代表一次资源的构建,compilation 实例能够访问所有的模块和它们的依赖。

一个 compilation 对象会对构建依赖图中所有模块,进行编译。 在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、 分块(chunk)、哈希(hash)和重新创建(restore)。

webpack执行顺序

webpack的自定义插件学习_第1张图片

自定义插件并挂载到Hook
class TestPlugin{
    constructor(str){
      console.log('str=============>',str)
    }
    apply(compiler){
            //同步钩子
        compiler.hooks.environment.tap("TestPlugin",() => {
          console.log("enviroment");
        })
        compiler.hooks.emit.tap("TestPlugin",(compilation) => {
            // console.log('compilation=============>',compilation)
        })
         //异步钩子  
        //emit是串行钩子,即钩子函数是一个个按顺序执行,例如以下需要花3s
        compiler.hooks.emit.tapAsync("TestPlugin",(compilation,callback) => {
            setTimeout(() => {
                console.log("emit Async 111");
                // console.log('compilation=============>',compilation)
                callback()
            }, 1000);
          })
        compiler.hooks.emit.tapPromise("TestPlugin",(compilation) => {
              return new Promise((resolve,reject)=>{
                setTimeout(() => {
                    console.log("emit Async 222");
                    resolve()
                }, 2000);
              })
            
          })
        //make是并行钩子,,以下需要花2s
        compiler.hooks.make.tapAsync("TestPlugin",(compilation,callback) => {
            setTimeout(() => {
                console.log("make Async 111");
                // console.log('compilation=============>',compilation)
                callback()
            }, 1000);

       
          })
        compiler.hooks.make.tapAsync("TestPlugin",(compilation) => {
              return new Promise((resolve,reject)=>{
                setTimeout(() => {
                    console.log("make Async 222");
                    resolve()
                }, 2000);
              })
            
          })
          //注册compilation的钩子
        compiler.hooks.compilation.tap('TestPlugin', (compilation) => {
            compilation.hooks.seal.tap('TestPlugin', () => {
              console.log('compilation.hooks.seal hook called');
            });
          });
    }


}
module.exports=TestPlugin
自定义clean-webpack-plugin

clean-webpack-plugin每次打包用于清除dist下目录的文件

class CleanWebpackPlugin {

    apply(complier){
        
        const outputPath =  complier.options.output.path
        const fs = complier.outputFileSystem
        complier.hooks.emit.tap('CleanWebpackPlugin',(compliation) => {
            this.removeFiles(fs,outputPath)
        })
    }

    removeFiles(fs,outputPath){
        const files = fs.readdirSync(outputPath)
        files.forEach((file) => {
           const pathfile = outputPath+"\\" +file
            if(fs.statSync(pathfile).isFile()){
                fs.unlinkSync(pathfile)
                return
            }else{
                    this.removeFiles(fs,pathfile)
            }
            //清空目录
           fs.rmdirSync(pathfile)
        })

      
    }
    //Api一行解决
    // removeFiles(fs,outputPath){
    //     fs.rmdirSync(outputPath,{recursive:true})
    // }

}
module.exports=CleanWebpackPlugin
自定义inline-chunk-plugin

将runtime等js文件改为内联的嵌入html的方式

runtime文件是用于解决缓存问题出现的

const HtmlWebpackPlugin = require('html-webpack-plugin');
class InlineChunkPlugin{
    constructor({tests=[]}){
        this.tests=tests
    }
    apply(compiler){
        compiler.hooks.compilation.tap('InlineChunkPlugin', (compilation) => {
            // console.log('The compiler is starting a new compilation...')
      
            // Static Plugin interface |compilation |HOOK NAME | register listener 
           const hooks =  HtmlWebpackPlugin.getHooks(compilation)
           hooks.alterAssetTagGroups.tap("InlineChunkPlugin",(assets) => {
            //    console.log('assets.headTags=============>',assets.headTags)
             /* 
                现在headTags的内容如下
               {
                tagName: 'script',
                voidTag: false,
                meta: { plugin: 'html-webpack-plugin' },
                attributes: { defer: true, type: undefined, src: 'static/js/runtime~main.js' }
              }, 
              要修改为如下
              {
                tagName: 'script',
                innerHTML: runtime文件内容
              }, 
              */
              
              assets.headTags=  this.getInlineChunk(assets.headTags,compilation.assets)
              //删除runtime文件
            

               Object.keys(compilation.assets).forEach((filepath)=>{
                   if(this.tests.some((test)=> test.test(filepath) )){
                       delete compilation.assets[filepath]
                   }
               })

           })
        }
        )

    }
    getInlineChunk(headTags,assets){
        return headTags.map ((tag) => {
            if(tag.tagName!=='script') return tag
            const filepath = tag.attributes.src;
            if(!this.tests.some((test)=> test.test(filepath) ))return tag
            return {
                meta: { plugin: 'InlineChunkPlugin' },
                tagName: 'script',
                innerHTML: assets[filepath].source()
            }
        })
    }
}
module.exports= InlineChunkPlugin

你可能感兴趣的:(前端,webpack,学习,javascript)