手写webpack plugin和loader

73 阅读1分钟

loader和plugin的区别

  • loader:由于webpack本身能解析的只有js和json文件,那么,针对css、图片等格式的文件就需要第三方的模块进行打包,所以loader的作用是让webpack拥有了加载和解析非javascript的能力
  • plugin: plugin可以扩展webpack的功能,让webpack具有更多的灵活性。在webpack运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的api改变输出结果
  • loader运行在打包文件之前;plugin在整个编译周期都起作用
  • loader的职责是单一的,只需要完成一种转换。

如何手写一个plugin

/** 
 * eg构建完成之后增加一个license的功能
 * 必须是一个类
 * 必须要有一个apply函数
 * 必须要调用compiler APi来影响打包结果
*/
class LicenseWebpackPlugin{
    constructor(params){
        this.params = params
    }
    apply(compiler){
        compiler.hooks.emit.tapAsync('',(compilation,cb)=>{
            console.log(compilation.assets)
            compilation.assets['LICENSE'] = {
                source: function(){
                    return 'license xxx ...'
                }
            }
            cb()
        })
    }
}
module.exports = LicenseWebpackPlugin

如何手写一个loader

同步loader

/**
 * replace.js
 * 这里不能用箭头函数,后期会改变this指向
 * eg: 同步loader,实现将w换成大写W
 */
module.exports = function(content){
    return content.replace(/w/g,'W')
}

异步loader

/**
 * async-loader.js
 * eg: 异步loader,同样实现文本修改
 */
const sleep = num=>new Promise((resolve)=>{
    setTimeout(()=>{
        resolve()
    },num)
})
module.exports = function(content){
    const callback = this.async()
    ;(async()=>{
        await sleep()
        content = content.replace(/W/,'www')
        callback(null,content)
    })()
}

引用

module.exports = {
    entry: 'xxx',
    module: {
        rules: [
            {
                test: /.js$/,
                use: [// loader解析顺序从后到前
                    path.resolve(__dirname,'./loaders/async-loader.js')
                    path.resolve(__dirname,'./loaders/replace.js')
                ]
            }
        ]
    }
}