您现在的位置是:首页 > 正文

【知识总结】 关于Webpack Loader知多少

2024-04-01 02:08:59阅读 5

loader是什么?

loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块。以供应用程序使用,以及被添加到依赖图中。loader 本质上是导出为函数的 JavaScript 模块。

在 webpack 使用过程中,经常会出现以下两种形式:

  1. webpack.config.js 配置文件中,去根据文件匹配信息,去配置 loader 相关信息;
  2. 是在 loader / plugin 中去修改、替换、生成的行内 loader 信息。
// webpack.config.js
{
  module: {
    rules: [
      {
        test: /.txt$/,
        use: [{
            loader: getLoader("a-loader.js"),
        }],
        enforce: "pre",
      },
      {
        test: /.txt$/,
        use: [{
            loader: getLoader("b-loader.js"),
        }],
        enforce: "post",
      },
    ],
  },
}
// app.js
import "/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt"

loader的分类

在 webpack 里,loader 可以被分为四类,分别是:

  1. 后置post
  2. 普通normal
  3. 行内inline
  4. 前置pre
enforce

对于post,normal,pre,主要取决于在配置里Rule.enforce的取值:pre || post,若无设置,则为normal。

注意:相对于的是 Rule,并非某个 loader。那么作用于的就是对应 Rule 的所有 loader。

inline

行内 loader 比较特殊,是在import / require的时候,将 loader 写入代码中。而对于inline而言,有三种前缀语法:

  • !:忽略normal loader
  • -!:忽略preloadernormal loader
  • !!:忽略所有 loader(pre / noraml / post )

行内 loader 通过!将资源中的 loader 进行分割,同时支持在 loader 后面,通过?传递参数,参数信息参考 loader.options 内容。

example

以a-loader为pre loader,b-loader为normal loader,c-loader为post loader为例:

module.exports = function (content) {
  console.log("x-loader");
  return content;
};

module.exports.pitch = function (remainingRequest, precedingRequest, data) {
  console.log("x-loader-pitch");
};

1、 无前缀信息

import "/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt"
c-loader-pitch
d-loader-pitch
b-loader-pitch
a-loader-pitch
a-loader
b-loader
d-loader
c-loader

2、!前缀信息

import "!/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt";
c-loader-pitch
d-loader-pitch
a-loader-pitch
a-loader
d-loader
c-loader

3、-!前缀信息

import "-!/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt";
c-loader-pitch
d-loader-pitch
d-loader
c-loader

4、!!前缀信息

import "!!/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt";
d-loader-pitch
d-loader

loader的优先级

四种 loader 调用先后顺序为:pre > normal > inline > post

在相同种类 loader 的情况下,调用的优先级为,自下而上,自右向左。(pitch 情况下,则反过来)。

举个🌰

{
  module: {
    rules: [
      {
        test: /.txt$/,
        use: [
          {
            loader: getLoader("a-loader.js"),
          },
        ],
        enforce: "post",
      },
      {
        test: /.txt$/,
        use: [
          {
            loader: getLoader("b-loader.js"),
          },
          {
            loader: getLoader("c-loader.js"),
          },
        ],
        enforce: "post",
      },
    ],
  },
}
a-loader-pitch
b-loader-pitch
c-loader-pitch
c-loader
b-loader
a-loader

loader调用链

每个 loader 都有自己的 normal 函数和 pitch 函数,而调用过程则是先根据从低到高的优先级顺序,调用 loader 各自的 pitch 函数,再由高到低调用各自的 normal 函数,其过程,更像是一个洋葱模型。

Loader - pitch

loader 总是 从右到左被调用。有些情况下,loader 只关心 request 后面的 元数据(metadata),并且忽略前一个 loader 的结果。在实际(从右到左)执行 loader 之前,会先 从左到右 调用 loader 上的 pitch 方法。

在这里插入图片描述

同步 / 异步 loader

如果是单个处理结果,可以在 同步模式 中直接返回。如果有多个处理结果,则必须调用 this.callback()。在 异步模式 中,必须调用 this.async()来告知 loader runner 等待异步结果,它会返回 this.callback() 回调函数。随后 loader 必须返回 undefined 并且调用该回调函数。

在 webpack 中,loader 可能会由于依赖于读取外部配置文件、进行网络请求等等原因,从而比较耗时。而此时如果进行同步操作,就会导致 webpack 阻塞住,所以 loader 会有同步 / 异步之分。

在 loader 中,可以通过两种方式返回数据:

  1. returnreturn只能返回content信息;
  2. callback
this.callback(
  err: Error | null,    // 错误信息
  content: string | Buffer,    // content信息
  sourceMap?: SourceMap,    // sourceMap
  meta?: any    // 会被 webpack 忽略,可以是任何东西(例如:AST、一些元数据啥的)。
);
同步 loader

对于同步 loader 而言,使用return或者this.callback均可以达到想要的效果。只是说,相对于returnthis.callback可以返回更多的信息。

module.exports = function(content, map, meta) {
  // return handleData(content);
  this.callback(null, handleData(content), handleSourceMap(map), meta);
  return; // 当调用 callback() 函数时,总是返回 undefined
};
异步 loader

对于异步 loader 而言,需要通过this.async(),来获取到callback函数。

module.exports = function(content, map, meta) {
  var callback = this.async();
  asycnHandleData(content, function(err, result) {
    if (err) return callback(err);
    callback(null, result, map, meta);
  });
};

网站文章

  • c++11之weak_ptr 使用介绍

    c++11之weak_ptr 使用介绍

    介绍 weak_ptr是弱智能指针对象,它不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的智能指针。将一个weak_ptr绑定到一个shared_ptr对象,不会改变shared_ptr的引用计数。一旦最后一个所指向对象的shared_ptr被销毁,所指向的对象就会被释放,即使此时有weak_ptr指向该对象,所指向的对象依然被释放。 代码验证如下: //defa...

    2024-04-01 02:08:53
  • 统一cas认证java_新版统一身份认证(CAS)

    申请需要提供以下信息,内容说明应用名称:格式为单位全称加应用,中间使用英文-连接,比如(学生处-离校系统),单位不需要再加厦门大学字样回调地址:格式为类似http://EXAMPLE.xmu.edu....

    2024-04-01 02:08:46
  • Mybatis设计分析一

    Mybatis设计分析一

    前面文章主要针对mybatis的进阶的使用有了个大的了解,包括缓存自定义 以及开启二级缓存机制,以及如何达到多数据源,按照我之前的写法通过路由 去解决 不同的数据源的问题,当然可以,有些时候其实也不用...

    2024-04-01 02:08:39
  • 两万常用汉字的拼音+首字母缩写+unicode编码对照表

    最近做项目遇到一项需求,为了隐藏汉字,对医院名称使用首字母代替,对医生名称用拼音代替。查阅了众多资料,比较分散,也不规范,做一个统一,问题包括以下几方面:1. 读出汉字的拼音首字母可通过Excel 公式实现;2. 读出汉字的拼音实现方法,基本需要借助编程,但是目前网上流传最广的版本是比较老旧的版本,不仅编码覆盖不全,而且有错误的mapping。3. 得到2万个常用的汉字并不容易,最...

    2024-04-01 02:07:59
  • Java参数传递

    要点 读完所有的评论以后,问题终于明白了,至少在一个主要问题上产生了混淆。某些评论认为我的节选是错的,因为对象是按引用传递的。 对象确实是按引用传递的;节选与这没有冲突。节选中说所有 参数都是按值 -- 另一个参数 -- 传递的。下面的说法是正确的:在 Java 应用程序中永远不会传递对象,而只传递对象引用。因此是按引用传递对象。但重要的是要区分参数是如何传递的,这才是该节选的意图。Java 应用

    2024-04-01 02:07:52
  • 【模板】用HTML编写邮件正文 | 各大邮箱几乎都会过滤css样式、js脚本等效果,如何用基础HTML编写?

    【模板】用HTML编写邮件正文 | 各大邮箱几乎都会过滤css样式、js脚本等效果,如何用基础HTML编写?

    2024-04-01 02:07:45
  • Javase | 字符编码、转义字符、方法执行过程中的 “内存分配”

    Javase | 字符编码、转义字符、方法执行过程中的 “内存分配”

    字符编码、转义字符、在控制台上输出 “反斜杠字符”、在控制台上输出 “单引号字符”、方法执行过程中的 “内存分配”.....

    2024-04-01 02:07:06
  • python 脚本第一行怎么写

    一、 python脚本第一行的写法:【#!/usr/bin/env python】。该语句告诉操作系统执行该脚本时,首先到env设置里查找python的安装路径,然后调用对应路径下的解释器程序完成操作...

    2024-04-01 02:06:59
  • jszip压缩服务器文件,使用JSZip压缩驻留在服务器上的PDF

    对不起,在这篇文章中缺少链接:这是我在stackoverflow上的第一篇文章,正如错误消息所说,“[我]需要至少10个声望才能发布2个以上的链接。”下载PDF(或任何二进制文件),你可以使用xhr....

    2024-04-01 02:06:52
  • linux mtp 代码,Linux MTP 的故事

    Linux下面有许许多多糟糕的故事,输入法算是其中之一,不过今天我们要讲的是另外一个故事。这个故事本质上和KDE关系不大,不过也算让我纠结了许久了。首先来介绍一下MTP,MTP是Media Trans...

    2024-04-01 02:06:15