有没有学过webpack?配置或者loader了解过吗?
loader是什么?
loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块。以供应用程序使用,以及被添加到依赖图中。loader 本质上是导出为函数的 JavaScript 模块。
在 webpack 使用过程中,经常会出现以下两种形式:
在 webpack.config.js 配置文件中,去根据文件匹配信息,去配置 loader 相关信息;
是在 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",
},
],
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// app.js
import "/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt"
1
2
loader的分类
在 webpack 里,loader 可以被分为四类,分别是:
后置post
普通normal
行内inline
前置pre
enforce
对于post,normal,pre,主要取决于在配置里Rule.enforce的取值:pre || post,若无设置,则为normal。
注意:相对于的是 Rule,并非某个 loader。那么作用于的就是对应 Rule 的所有 loader。
inline
行内 loader 比较特殊,是在import / require的时候,将 loader 写入代码中。而对于inline而言,有三种前缀语法:
!:忽略normal loader
-!:忽略preloader 和normal 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
2
3
4
5
6
7
8
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
1
2
3
4
5
6
7
8
9
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
1
2
3
4
5
6
7
3、-!前缀信息
import "-!/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt";
c-loader-pitch
d-loader-pitch
d-loader
c-loader
1
2
3
4
5
4、!!前缀信息
import "!!/Users/jiangyuereee/Desktop/loader/d-loader.js!./txt.txt";
d-loader-pitch
d-loader
1
2
3
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",
},
],
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
a-loader-pitch
b-loader-pitch
c-loader-pitch
c-loader
b-loader
a-loader
1
2
3
4
5
6
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 中,可以通过两种方式返回数据:
return:return只能返回content信息;
callback
this.callback(
err: Error | null, // 错误信息
content: string | Buffer, // content信息
sourceMap?: SourceMap, // sourceMap
meta?: any // 会被 webpack 忽略,可以是任何东西(例如:AST、一些元数据啥的)。
);
1
2
3
4
5
6
同步 loader
对于同步 loader 而言,使用return或者this.callback均可以达到想要的效果。只是说,相对于return,this.callback可以返回更多的信息。
module.exports = function(content, map, meta) {
// return handleData(content);
this.callback(null, handleData(content), handleSourceMap(map), meta);
return; // 当调用 callback() 函数时,总是返回 undefined
};
1
2
3
4
5
异步 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);
});
};
————————————————
版权声明:本文为CSDN博主「椰卤工程师」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42224055/article/details/120687534
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术