开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
1. loader 的执行顺序
loader是一个到处为函数的模块,入参为上一个loader的结果或者资源文件 webpack Compiler编译会得到最后一个loader产生的结果。
2. loader的分类
loader的类型和loader自己是没什么关系的,用enforce来控制。loader分为4种类型:normal,post,pre,inline; loader 的叠加顺序 = post(后置)+inline(内联)+normal(正常)+pre(前置)
let request = `inline-loader1!inline-loader2!${entryFile}`;
let rules = [
{
test: /\.js$/,
use: ["normal-loader1", "normal-loader2"],
},
{
test: /\.js$/,
enforce: "post",
use: ["post-loader1", "post-loader2"],
},
{
test: /\.js$/,
enforce: "pre",
use: ["pre-loader1", "pre-loader2"],
},
];
以下为这几种rules中的loader执行顺序
|- post-loader1-pitch
post-loader2-pitch
inline-loader1-pitch
inline-loader2-pitch
normal-loader1-pitch
normal-loader2-pitch
pre-loader1-pitch
pre-loader2-pitch
|- pre-loader2
pre-loader1
normal-loader2
normal-loader1
inline-loader2
inline-loader1
post-loader2
post-loader1
loader总是从右到左被调用。有些情况下,loader只关心request后面的元数据(metadata),并且忽略前一个loader的结果。在实际(从右到左)执行loader之前,会先 从左到右调用loader上的pitch方法。
3. loader上下文
loader context 表示在loader内使用this可以访问的一些方法或属性。
function runLoaders(options, finalCallback) {
//resource要处理的资源,或者说要编译的模块路径
//loaders处理此路径的loaders
//context指的是loader函数在执行的时候this指针
//readResource读取文件的方法fs.readFile
const { resource, loaders = [], context = {}, readResource } = options;
//loaders现在是一个loader模块的绝对路径,转成一个对象
const loaderObjects = loaders.map(createLoaderObject);
const loaderContext = context;//这个对象就是loader执行的时候的this指针
loaderContext.resource = resource;//加载的模块
loaderContext.readResource = readResource;//读取文件的方法
loaderContext.loaders = loaderObjects;//存放loaders对象数组
loaderContext.loaderIndex = 0;//当前正在处理的loader的索引
loaderContext.callback = null;//可以手工调用此方法向后执行下一个loader
loaderContext.async = null;//可以把loader运行从同步变为异步,并返回this.callback
}
loader的执行过程
4. less-loader
完整的loader比较复杂,这里是一个简单实现。
const less = require('less');
function loader(source) {
let callback = this.async();
less.render(source, { filename: this.resource }, (err, output) => {
callback(err,`module.exports = ${JSON.stringify(output.css)}`);
});
}
module.exports = loader;
转换前
'@color:red;\n#root{\n color:@color;\n}'
转换后
css:'#root {\n color: red;\n}\n'