自定义loader、plugin,两者区别

907 阅读2分钟

loader

定义:文件加载器,用来对各种资源进行转换

特点

  • loader的执行顺序和代码书写的顺序是相反的:从右到左执行
  • 第一个执行的loader会接收源文件做为参数,下一次执行的loader会接收前一个loader执行的返回值做为参数。

自定义loader

loader就是一个node模块,它输出了一个函数当某种资源需要用这个loader转换时,这个函数就会被调用。并且,这个函数可以通过提供给它的this上下文访问loader API。

所以loader大概就是这样一个javascript文件:

module.exports = function(src){
 // 可以通过this访问loader API
 // this是由webpack提供的,可以直接使用
}
  • 例如:写一个loader,功能是对txt文件的内容反转。有个test.txt文件,内容为abcdefg
/*
* 首先应该设置一个loaders文件夹
* 在loaders文件夹下写txt-loader文件夹
* txt-loader文件夹下写一个index.js文件,内容如下
*/
function txtLoader(source){
   // source就是txt文件的内容(abcdefg),下面对内容进行处理
   var result = source.split('').reverse().join('')
   // 返回js源码,必修是string或buffer
   return `module.exports = '${result}'`;
}
module.exports = txtLoader;

/*
* webpack.config.js文件中module下的rules对txt文件进行txt-loader 处理
*/
  • 新建清除console语句的loader

    • 首先新建一个dropConsole.js文件
// source:表示当前要处理的内容
const reg = /(console.log()(.*)())/g
module.exports = function(source) {
   // 通过正则表达式将当前处理内容中的console替换为空字符串
   source = source.replace(reg,'')
   // 在把处理好的内容return出去。输入输出都是字符串的原则,并可达到链式调用的目的供下一个loader处理
   return source
}
  • 在webpack的配置文件中引入
module:{
rules:[
   {
   test:/.js/,
   use:[
      {
        loader:path.resolve(__dirname,'./dropConsole.js'),// loader的绝对路径
        options:{
           name:'前端'
        }
      }
   ]}
]}

plugin

定义

在webpack运行的声明周期中会广播许多事件,plugin可以监听这些事件,在特定的时刻调用webpack提供的API执行相应的操作。

作用

  • clean-webpack-plugin 这个插件可以在每次打包输出前清空文件夹
  • mini-css-extract-plugin 把css样式从js文件中提取到单独的css文件中

自定义plugin

plugin是一个具有apply方法的js对象。apply方法会被webpack的compiler(编译器)对象调用,并且compiler对象可在整个compilation(编译)生命周期内访问。

主要步骤;

  • 编写一个JavaScript命名函数或者class(ES6语法)
  • 在它的原型上定义一个apply方法
  • 指定挂载的webpack事件钩子
  • 处理webpack内部实例的特定数据
  • 功能完成后调用webpack提供的回调
/*
* 首先在项目中定义一个plugins文件夹
*
*/
class MdToHtmlPlgin{  
   constructor(doneCallback, failCallback) {
    // 存下在构造函数中传入的回调函数
    this.doneCallback = doneCallback;
    this.failCallback = failCallback;
  }

  apply(compiler) {
    compiler.plugin('done', (stats) => {
        // 在 done 事件中回调 doneCallback
        this.doneCallback(stats);
    });
    compiler.plugin('failed', (err) => {
        // 在 failed 事件中回调 failCallback
        this.failCallback(err);
    });
  }
}
module.exports = MdToHtmlPlgin
/*
* apply方法会被webpack compiler调用,并且compiler对象可在整个编译生命周期访问
*
*/
打包文件清单.plugin

需求:每次webpack打包之后,自动产生一个打包文件清单,记录打包之后的文件夹dist里所有的文件的一些信息

class FileList {
   static defaultoptions = {
      outputFile:'assets.md'
   };
   constructor(options = {}){
      // 可以接收自定义的options,如文件名等,进行合并
      this.options = {...FileList.defaultOptions,...options}
   }
   apply(compiler){
      // 在emit钩子里执行,是异步钩子
      compiler.hooks.emit.tapAsync('FileList',(compilation,callback)=>{
          const fileListName = this.options.outputFile
          let len = Object.keys(compilation.assets).length
          let content = `#一共有${len}个文件\n\n`
          for(let filename in compilation.assets){
            content += `- ${filename}\n`
          }
          compilation.assets[fileListName] = {
            source:function(){
               return content
            }
            size:function(){
                return content.length
            }
          }
          callback()
      })
   }
}

module.exports = FileList

区别

  • loader 用于加载某些资源文件。 因为webpack 本身只能打包commonjs规范的js文件,对于其他资源例如 css,图片,或者其他的语法集,比如 jsx, coffee,是没有办法加载的。 这就需要对应的loader将资源转化,加载进来。从字面意思也能看出,loader是用于加载的,它作用于一个个文件上。

  • plugin 用于扩展webpack的功能。它直接作用于 webpack,扩展了它的功能。当然loader也同时变相的扩展了 webpack ,但是它只专注于转化文件(transform)这一个领域。而plugin的功能更加的丰富,而不仅局限于资源的加载。

总结

loader 用于加载待打包的资源,plugin 用于扩展 webpack