webpack提供了loader功能来预处理文件,下面介绍几种拷贝静态资源文件的loader以及它们之间的区别。

文件loader

loader 介绍
raw-loader 加载文件原始内容(utf-8)
val-loader 将代码作为模块执行,并将 exports 转为 JS 代码
file-loader 将文件发送到输出文件夹,并返回(相对)URL
url-loader 像 file loader 一样工作,但如果文件小于限制,可以返回 data URL
raw-loader

raw-loader的功能非常简单,直接返回JSON.stringify后的内容。

raw-loaderraw-loader@0.5.1
1
2
3
4
module.exports = function(content) {
...
return "module.exports = " + JSON.stringify(content);
}
val-loader

val-loader可以将以字符串形式定义的代码作为模块执行,返回对应的模块。

一个例子
1
2
3
4
5
6
7
8
// findAnswer.js
function findAnswer() {
return {
code: 'module.exports = 42;'
};
}

module.exports = findAnswer;

通过webpack配置val-loader来解析。

1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: require.resolve('./findAnswer.js'),
use: [{
loader: 'val-loader'
}]
}]
}
};

结果module.exports = 42语句会以模块形式产出。

1
2
3
4
5
6
7
// bundle.js
(function(modules) {...})([
...,
(function(module, exports) {
module.exports = 42;
})
])

更详细的例子可以参考val-loaderGitHub主页。

实现
val-loaderval-loader@1.0.2
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
28
function valLoader(content) {
const options = loaderUtils.getOptions(this);
// 1.将content按照exports模块执行,得到暴露的function
const exports = this.exec(content, this.resource);
const func = (exports && exports.default) ? exports.default : exports;

// 2.执行exports出去的function,得到带code属性的对象
const result = func(options);

if (result && typeof result.then === 'function') {
const callback = this.async();

// 3.通过processResult处理对象
result.then(res => processResult(this, res), callback);

return;
}

// 3.通过processResult处理对象
processResult(this, result);
}

function processResult(loaderContext, result) {
// 4.将result.code作为loader结果返回
loaderContext.callback(null, result.code, result.sourceMap || null, result.ast || null);
}

export default valLoader;
file-loader

file-loader主要是指导webpack将指定文件拷贝到输出文件夹。同时,在require文件的地方会返回文件的–绝对路径–。
产生文件的功能使用了webpack loader的APIthis.emitFile。这是webpack独有的。

file-loaderfile-loader@0.11.2
1
2
3
4
5
6
7
8
9
module.exports = function(content) {
...

if (query.emitFile === undefined || query.emitFile) {
this.emitFile(outputPath, content);
}

return "module.exports = " + publicPath + ";";
}
url-loader

url-loader在file-loader的基础上加了一个data URL的功能。传给url-loader一个限制值,如果处理的文件小于这个值,loader将会把文件转化为base64的data URL输出。大于限制的文件则交给引入的file-loader处理。

url-loaderurl-loader@0.5.9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = function(content) {
...

if(!limit || content.length < limit) {
if(typeof content === "string") {
content = new Buffer(content);
}

return "module.exports = " + JSON.stringify("data:" + (mimetype ? mimetype + ";" : "") + "base64," + content.toString("base64"));
}

var fileLoader = require("file-loader");

return fileLoader.call(this, content);
}

参考链接

https://doc.webpack-china.org/loaders/