Webpack自定义Loader和Plugin方法

手写Loader

Loader 本质上是导出函数的 JavaScript 模块,而该模块导出的函数被称为 Normal Loader,在开发 Loader时,我们可以在导出的函数上添加一个 pitch 属性,它的值也是一个函数。该函数被称为 PitchingLoader。Loader执行时会先执行Pitching Loader再执行Normal Loader, Pitching Loade的执行顺序是 从左到右,而 Normal Loader 的执行顺序是 从右到左。

借用他人示意图如下:
在这里插入图片描述

开发之前需要明确的点

  • 首先明确loader默认导出一个函数,接受匹配到的文件资源字符串和SourceMap
  • 处理异步loader时,需要通过loader本身提供的回调函数callback
  • 加载本地loader的方法是通过webpack提供的resolveLoader属性,来告诉webpack从哪里解析本地loader
  • 可以通过工具loader-utils的getOptions方法获得参数,通过schema-utils的validate方法来检验获得的参数是否符合规则
const { getOptions } = require("loader-utils");
const { validate } = require("schema-utils");
const schema = require("./schema.json");
module.exports = function (source, map) {
  const options = getOptions(this);
  const configuration = { name: "Loader Name"};
  validate(schema, options, configuration);
  //省略其他代码
}

手写Plugin

在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果。plugin的本质是类;我们在定义plugin时,其实是在定义一个类。

//plugins/MyPlugin.js
class MyPlugin {
  constructor(options) {
    console.log("Plugin被创建了");
    console.log(options);
    this.options = options;
  }
  apply (compiler) {
    //注册完成的钩子
    compiler.hooks.done.tap("MyPlugin", (compilation) => {
      console.log("compilation done");
    });
  }
}
//webpack.config.js
module.exports = {
  plugins: [
    new MyPlugin({ title: 'MyPlugin' })
  ],
}

我们在构建插件时就能通过options获取配置信息,对插件做一些初始化的工作。在构造函数中我们发现多了一个apply函数,它会在webpack运行时被调用,并且注入compiler对象;其工作流程如下

  1. webpack启动,执行new myPlugin(options),初始化插件并获取实例
  2. 初始化complier对象,调用myPlugin.apply(complier)给插件传入complier对象
  3. 插件实例获取complier,通过complier监听webpack广播的事件,通过complier对象操作webpack

这里又有一个compilation对象,它和上面提到的compiler对象都是Plugin和webpack之间的桥梁:

  • compiler对象包含了 Webpack 环境所有的的配置信息。这个对象在启动 webpack
    时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack
    环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。
  • compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。当运行webpack
    开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。compilation
    对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。

了解了compiler和compilation的区别,我们就来尝试一个简单的示例插件,在打包目录生成一个filelist.md文件,文件的内容是将所有构建生成文件展示在一个列表中:

class FileListPlugin {
    apply(compiler){
        compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback)=>{
            var filelist = 'In this build:\n\n';
            // 遍历所有编译过的资源文件,
            // 对于每个文件名称,都添加一行内容。
            for (var filename in compilation.assets) {
                filelist += '- ' + filename + '\n';
            }
            // 将这个列表作为一个新的文件资源,插入到 webpack 构建中:
            compilation.assets['filelist.md'] = {
                source: function() {
                    return filelist;
                },
                size: function() {
                    return filelist.length;
                }
            };
            callback();
        })
    }
}
module.exports = FileListPlugin

我们这里用到了assets对象,它是所有构建文件的一个输出对象,打印出来大概长这样:

{
  'main.bundle.js': { source: [Function: source], size: [Function: size] },
  'index.html': { source: [Function: source], size: [Function: size] }
}

我们手动加入一个filelist.md文件的输出;打包后我们在dist文件夹中会发现多了这个文件:

In this build:

- main.bundle.js
- index.html
  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值