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

通过 returnthis.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 分钟前
PHP基本语法总结
开发语言·前端·html·php
新缸中之脑12 分钟前
Llama 3.2 安卓手机安装教程
前端·人工智能·算法
hmz85615 分钟前
最新网课搜题答案查询小程序源码/题库多接口微信小程序源码+自带流量主
前端·微信小程序·小程序
看到请催我学习21 分钟前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
blaizeer1 小时前
深入理解 CSS 浮动(Float):详尽指南
前端·css
速盾cdn1 小时前
速盾:网页游戏部署高防服务器有什么优势?
服务器·前端·web安全
小白求学11 小时前
CSS浮动
前端·css·css3
什么鬼昵称1 小时前
Pikachu-csrf-CSRF(POST)
前端·csrf
XiaoYu20022 小时前
22.JS高级-ES6之Symbol类型与Set、Map数据结构
前端·javascript·代码规范
golitter.2 小时前
Vue组件库Element-ui
前端·vue.js·ui