webpack源码解析:file-loader和url-loader
file-loader 和 url-loader 相对简单⼀些,如果没有看过代码可能⼀下想不到 file-loader 是如何⼯作的。其实他们都依靠 webpack 提供的强⼤的API,⾃⼰本⾝并没有做多少⼯作,
完全不⽤担⼼读写⽂件的问题,因为这些webpack已经帮你封装好了。
file-loader
file-loader 并不会对⽂件内容进⾏任何转换,只是复制⼀份⽂件内容,并根据配置为他⽣成⼀个唯⼀的⽂件名。
file-loader 的⼯作流程如下:
通过 loaderUtils.interpolateName ⽅法可以根据 options.name 以及⽂件内容⽣成⼀个唯⼀的⽂件名 url(⼀般配置都会带上hash,否则很可能由于⽂件重名⽽冲突)
通过 itFile(url, content) 告诉 webpack 我需要创建⼀个⽂件,webpack会根据参数创建对应的⽂件,放在 public path ⽬录下。
返回 'ports = webpack_public_path + '+ JSON.stringify(url) + ‘;’ ,这样就会把原来的⽂件路径替换为编译后的路径
对file-loader 中最重要的⼏⾏代码解释如下(我们⾃⼰来实现⼀个 file-loader 就只需要这⼏⾏代码就⾏了,完全可以正常运⾏且⽀持 name 配置):
var loaderUtils = require('loader-utils')
// 获取options,就是 webpack 中对 file-loader 的配置,⽐如这⾥我们配置的是 `name=[name]_[hash].[ext]`
// 获取到的就是这样⼀个k-v 对象 { name: "[name]_[hash].[ext]" }
const options = Options(this) || {};
// 这是 loaderUtils 的⼀个⽅法,可以根据 name 配置和 content 内容⽣成⼀个⽂件名。为什么需要⽂件内容呢?这是为了保证当⽂件内容没有发⽣变化的时候,名字中的 [hash] 字段也不会变。可以理解为⽤⽂件的内容作了⼀个hash  let url = loaderUtils.interpolateName(this, options.name, {
content
})
// 这⾥要⽤到⼀个变量,就是 __webpack_public_path__ ,这是⼀个由webpack提供的全局变量,是public的根路径
// 参见:/guides/public-path/#on-the-fly
// 这⾥要注意⼀点:这个返回的字符串是⼀段JS,显然,他是在浏览器中运⾏的
// 举个栗⼦:
// css源码这样写: background-image: url('a.png')
// 编译后变成: background-image: require('xxxxxx.png')
// 这⾥的 require 语句返回的结果,就是下⾯的 exports 的字符串,也就是图⽚的路径
return 'ports = __webpack_public_path__ + '+ JSON.stringify(url)
}
// ⼀定别忘了这个,因为默认情况下 webpack 会把⽂件内容当做UTF8字符串处理,⽽我们的⽂件是⼆进制的,当做UTF8会导致图⽚格式错误。
// 因此我们需要指定webpack⽤ raw-loader 来加载⽂件的内容,⽽不是当做 UTF8 字符串传给我们
如果我们不⽀持 name 参数,甚⾄只需要两⾏代码就能实现。
url-loader
url-loader 并不是复制⽂件,⽽是把⽂件做base64编码,直接嵌⼊到CSS/JS/HTML代码中。
url-loader 的⼯作流程如下:
获取 limit 参数
如果⽂件⼤⼩在 limit 之类,则直接返回⽂件的 base64 编码后内容
如果超过了 limit ,则调⽤ `file-loader
因为逻辑⽐较简单,这⾥直接放上源码以及我添加的注释:
// 获取 options 配置,上⾯已经讲过了就不在重复
var options =  Options(this) || {};
// Options `dataUrlLimit` is backward compatibility with first loader versions
// limit 参数,只有⽂件⼤⼩⼩于这个数值的时候我们才进⾏base64编码,否则将直接调⽤ file-loader
var limit = options.limit || (this.options && this.options.url && this.options.url.dataUrlLimit);
if(limit) {
limit = parseInt(limit, 10);
}
var mimetype = options.mimetype || options.minetype || mime.sourcePath);
// No limits or limit more than content length
if(!limit || content.length < limit) {
if(typeof content === "string") {
url编码和utf8区别content = new Buffer(content);
}
// 直接返回 base64 编码的内容
return "ports = " + JSON.stringify("data:" + (mimetype ? mimetype + ";" : "") + "base64," + String("base64"));
}
// 超过了⽂件⼤⼩限制,那么我们将直接调⽤ file-loader 来加载
var fallback = options.fallback || "file-loader";
var fallbackLoader = require(fallback);
return fallbackLoader.call(this, content);
}
// ⼀定别忘了这个,因为默认情况下 webpack 会把⽂件内容当做UTF8字符串处理,⽽我们的⽂件是⼆进制的,当做UTF8会导致图⽚格式错误。
// 因此我们需要指定webpack⽤ raw-loader 来加载⽂件的内容,⽽不是当做 UTF8 字符串传给我们
// 参见: webpack.github.io/docs/loaders.html#raw-loader

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。