Webpack - 自定义 Loader

Loader Interface

loader 本质上是 JS 函数。loader runner 会调用此函数。

js 复制代码
function webpackLoader(content, map, meta) {
  // ...
}

参数说明:

  • content: string | Buffer

    • 资源源文件内容 或者 是上一个 loader 处理的结果;
  • map: object

    • SourceMap 数据
  • meta: any

    • meta 数据,可以是任何内容(可以是其他 loader 传递过来的参数)

同步 Loader

通过 return 或 this.callback 都可以同步地返回转换后的 content。

函数中的 this 作为上下文会被 webpack 填充。

js 复制代码
// 通过 return 同步返回转换后的 content
module.exports = function (content, map, meta) {
  return someSyncOperation(content);
};

// this.callback 可以传递更多参数
module.exports = function (content, map, meta) {
  this.callback(null, someSyncOperation(content), map, meta);
  return; // 当调用 callback() 函数时,总是返回 undefined
};

异步 Loader

通过 this.async 获取 callback 函数。

js 复制代码
module.exports = function (content, map, meta) {
  var callback = this.async();
  someAsyncOperation(content, function (err, result) {
    if (err) return callback(err);
    callback(null, result, map, meta);
  });
};

由于同步计算过于耗时,建议尽可能地使你的 loader 异步化。但如果计算量很小,同步 loader 也是可以的。

"Raw" Loader

默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 raw 为 true,loader 可以接收原始的 Buffer。每一个 loader 都可以用 String 或者 Buffer 的形式传递它的处理结果。complier 将会把它们在 loader 之间相互转换。

js 复制代码
// "Raw" Loader 常用来处理 图片,字体图标等媒体资源
module.exports = function (content) {
  return someSyncOperation(content);
};

module.exports.raw = true;

Pitching Loader

loader 总是 从右到左被调用。在实际(从右到左)执行 loader 之前,会先 从左到右 调用 loader 上的 pitch 方法。

js 复制代码
// 传递给 pitch 方法的 data,在执行阶段也会暴露在 this.data 之下
module.exports = function (content) {
  return someSyncOperation(content, this.data.value);
};

module.exports.pitch = function (remainingRequest, precedingRequest, data) {
  data.value = 42;
};
rust 复制代码
比如处理 scss 样式文件时,webpack 有以下配置:

use: ['style-loader', 'css-loader', 'sass-loader']

执行顺序:
-> style-loader pitch 
-> css-loader pitch
-> sass-loader pitch 
-> sass-loader 
-> css-loader 
-> style-loader

如果 css-loader 的 pitch 方法 return 了一个结果,将跳过剩余 loader

顺序如下:
-> style-loader pitch 
-> css-loader pitch
-> style-loader

The Loader Context

webpack.docschina.org/api/loaders...

loader context 表示在 loader 内使用 this 可以访问的一些方法或属性。

示例

js 复制代码
// 清除 console.log 的 loader
module.exports = function (source, map, meta) {
  const newSource = source.replace(/console.log(.+?)(;\n)?/g, "");
  this.callback(null, newSource, map, meta);
};

// 简易 style-loader
module.exports.pitch = function (remainingRequest) {
  // 将绝对路径转换为相对路径后,直接引用
  const relativePath = remainingRequest
    .split("!")
    .map((absolutePath) => {
      // 将每个绝对路径转换为相对路径
      return this.utils.contextify(this.context, absolutePath);
    })
    .join("!");
  const newSource = `
    import style from "!!${relativePath}";
    const _style = document.createElement("style");
    _style.innerHTML = style;
    document.head.appendChild(_style);
  `;
  return newSource;
};

// 简易 file-loader
const loaderUtils = require("loader-utils");
module.exports = function (source) {
  // 根据文件内容生成 hash
  const interpolatedName = loaderUtils.interpolateName(
    this,
    "[hash].[ext][query]",
    {
      content: source,
    }
  );
  // 将文件输出
  this.emitFile(interpolatedName, source);
  return `module.exports = "${interpolatedName}"`;
};
module.exports.raw = true;

// 简易 babel-loader 
const babel = require("@babel/core");
const schema = require("./schema.json");

module.exports = function (source) {
  // 异步loader
  const callback = this.async();
  // schema 对参数进行校验
  const options = this.getOptions(schema);

  babel.transform(source, options, function (err, result) {
    if (err) callback(err);
    callback(null, result.code);
  });
};

// schema.json
{
  "type": "object",
  "properties": {
    "presets": {
      "type": "array"
    }
  },
  "additionalProperties": true
}
相关推荐
知了学历孙老师2 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
ShineWinsu4 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说5 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵6 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot6 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot6 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI7 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance7 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端
补码缩写7 小时前
WebCodecs选编码器,探测之后还要验解码和播放
前端
大文说跨境7 小时前
亚马逊多账号管理浏览器怎么选?云登/紫鸟/AdsPower 对比
java·前端·自动化