序言
在学习之前先抛出三个问题,我们根据这三个问题深入学习 loader 。
- 什么是 loader ,它能干什么。
- 为什么需要 loader 。
- 如何使用 loader ,有哪些要掌握的核心。
什么是 loader ?
这是 webpack 官网的宣传图,我们可以看到,左侧各种类型的文件,统一打包成右边被浏览器识别支持的文件,那么这个转换的过程是如何实现的呢,没错就是 webpack 的核心概念之一( loader)实现的。
- loader 让 webpack 能够处理其他类型的文件,并将它们转换为有效模块。
- loader 本质是一个函数,导出为函数的 JavaScript 模块。
- 简单说就是将各种类型的文件,转换成 JS 模块。
为什么需要loader
因为 webpack 只能理解 JavaScript和 JSON文件。所以需要一个模块来帮它处理其他类型的文件,loader 就是做这件事情的模块。
webpack常用的loader
样式:style-loader、css-loader、less-loader、sass-loader 等
文件:raw-loader、file-loader 、url-loader 等
编译:babel-loader、coffee-loader 、ts-loader 等
校验测试:mocha-loader、jshint-loader 、eslint-loader 等
为什么有这么多种 loader 呢,是因为一种 loader 处理相应的文件,这样的职责单一的设计,可以高度复用和灵活组合。
loader怎么用
首先 loader 是辅助 webpack 的模块 ,所以要配置 webpack.config 文件指定 loader 的执行区间和执行方式,我们以一个 sass-loader 的例子演示一下使用。
- 首先匹配要处理的文件,通过 test,正则过滤出 scss 文件。
- 经过 sass-loader 转换 sass 文件为 css 文件, 并且包装一层 module.exports 成为一个 js module 。
- 通过 style-loader 将创建一个style 标签将上面转换完成的 css 文件嵌入 html 中。
- 最后 css-loader 处理其中的
@import
和url()
。因为 webpack 不认识,所以将其转化成 require 形式。
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use:[
{loader:'style-loader'},
{loader:'css-loader',options:{sourceMap:true,modules:true}},
{loader:'sass-loader',options:{sourceMap:true}}
],
exclude:/node_modules/,
enforce: "post",
}
]
}
}
深入 loader
我们已经知道了 loader 的概念和基本使用,所以接下来会探究一下 loader 的分类和执行流程。通过上例,我们发现还有一个 enforce: "post"
配置,这就是loader 分类的配置。
enforce ( loader 分类)
类别与优先级
- 在 webpack 中 loader 可以被分为四类,分别是 :普通
normal
,前置pre
,行内inline
,后置post
。 - 普通
normal
,前置pre
,后置post
,通过 enforce 可以进行分类设置,若无设置,则默认为 normal。 - 行内
inline
比较特殊,是在 import / require 的时候,直接写入代码中,用来过滤其他的 loader 。 - 四种loader调用先后顺序为:pre > normal > inline > post 。
inline(行内 loader )
使用方法是在 import / require
的时候,将他的三种前缀语法写入代码中:
!
: 忽略 normal-loader。-!
: 忽略 pre-loader 和 normal-loader.!!
: 忽略所有 loader (pre / normal / post)
行内 loader 通过 !
控制资源中的 loader,同时支持在 loader 后面通过 ?
传递参数。
Tip:
该分类是相对于 rules ,并非是某个 loader ,只要在当前这个 rules 范围内的所有 loader 都遵循此设定。
实例
假设我们有4个 loader ,分别为 pre-loader ,normal-loader ,post-loader ,inline-loader。
以上 loader 均为:
module.exports = function (content) {
console.log("x-loader");
return content;
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
console.log("x-loader-pitch");
};
- 无前缀信息时
import "/Users/jiangyuereee/Desktop/loader/inline-loader.js!./txt.txt"
post-loader-pitch
inline-loader-pitch
normal-loader-pitch
pre-loader-pitch
pre-loader-pitch
normal-loader-pitch
inline-loader-pitch
post-loader-pitch
我们可以发现,执行顺序是按照我们上文提到的优先级顺序进行排列,并且触发方式类似于洋葱模型。
- !前缀信息
import "!/Users/jiangyuereee/Desktop/loader/inline-loader.js!./txt.txt"
post-loader-pitch
inline-loader-pitch
pre-loader-pitch
pre-loader-pitch
inline-loader-pitch
post-loader-pitch
我们看到 normal-loader 并没有触发,所以过滤成功。
- -!前缀信息
import "-!/Users/jiangyuereee/Desktop/loader/inline-loader.js!./txt.txt"
post-loader-pitch
inline-loader-pitch
inline-loader-pitch
post-loader-pitch
我们看到 normal-loader 和 pre-loader 并没有触发,所以过滤成功。
- !!前缀信息
import "!!/Users/jiangyuereee/Desktop/loader/inline-loader.js!./txt.txt"
post-loader-pitch
post-loader-pitch
我们看到只有 inline-loader 触发,所以过滤成功。
- 当出现相同的 loader 的情况下,调用的优先级为,从低到高,自右往左。(pitch情况下,则相反)
Loader-pitch
- loader 的调用过程:在从右往左调用 loader 方法之前都会从左往右调用一遍 loader上面的 pitch 方法。
- loader 的熔断机制
一旦一个 pitch 返回了结果,那么直接熔断,不会执行后面的 pitch ,直接将现有结果传递给前一个 loader 。
我们看到上图中 loader2.pitch 返回了结果,直接把结果传递给 loader1,剩下的都不会触发了。
同步 / 异步 loader
在官方文档中有描述:
如果是单个处理结果,可在同步模式中直接返回,但是如果有多个结果,则要调用 this.callpack()
。在异步模式中,必须调用 this.async()
来告知 loader runner 等待异步结果,它会返回 this.callback()
回调函数,随后 loader 必须返回 undefined ,并且调用该回调函数。
在 webpack 中,loader 会依赖于读取外部配置文件,进行网络请求等,如果同步操作,会造成进程堵塞。所以loader 会有同步 / 异步之分。
在 loader 中,可以通过两种方式返回数据:
- return :只能返回 content。
- callback :可以返回
err : Error | null
(错误信息)content : string | Buffer
(content信息)sourceMap : SourceMap
(sourceMap)meta? : any
(奇怪的数据,AST等等)
同步 loader
module.exports = function(content, map, meta) {
// return handleData(content);
this.callback(null, handleData(content), handleSourceMap(map), meta);
return; // 当调用 callback() 函数时,总是返回 undefined
};
异步 loader
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);
});
};
总结: 要注意的是,异步要通过 this.async
来获取 callback。
loader的输出
由loader的返回方法 callback 可知,当 loader 链路到了最后一个 loader 的时候,compiler 期待得到的结果是可以转换为String
的 Buffer
或者直接是个 String
。表示当前模板处理后的 JS
源码。根据返回参数得知,还可以传递一个 sourceMap
。
除去正常的 loader 输出的 JS 源码,还可以根据 this.emitFile
进行额外输出文件。
emitFile(
name: string,
content: Buffer|string,
sourceMap?: {...}
);
相关使用工具
- webpack 官方中文文档。
- Loader 机制。
- Loader-runner调试工具。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!