细说webpack源码之compile流程-rules参数处理技巧(2(3)
接下来的resourceQuery、compiler、issuer先跳过,脚手架没有,不知道怎么写。
loader
下面是另一块主要配置loader(s),这里loader与loaders作用一样的,当初还头疼啥区别:
const loader = rule.loaders || rule.loader;
// 单loader情况
if (typeof loader === "string" && !rule.options && !rule.query) {
checkUseSource("loader");
newRule.use = RuleSet.normalizeUse(loader.split("!"), ident);
}
// loader配合options或query出现
else if (typeof loader === "string" && (rule.options || rule.query)) {
checkUseSource("loader + options/query");
newRule.use = RuleSet.normalizeUse({
loader: loader,
options: rule.options,
query: rule.query
}, ident);
}
// options与query同时出现报错
else if (loader && (rule.options || rule.query)) {
throw new Error(RuleSet.buildErrorMessage(rule, new Error("options/query cannot be used with loaders (use options for each array item)")));
}
/*
处理这种愚蠢用法时:
{
test: /\.css$/,
loader: [{ loader: 'less-loader' }, { loader: 'css-loader' }]
}
*/
else if (loader) {
checkUseSource("loaders");
newRule.use = RuleSet.normalizeUse(loader, ident);
}
// 单独出现options或者query报错
else if (rule.options || rule.query) {
throw new Error(RuleSet.buildErrorMessage(rule, new Error("options/query provided without loader (use loader + options)")));
}
之前举例的babel-loader就是第一种单loader配置,这里使用vue-loader嵌套的css配置作为示例。
首先normalizeUse方法如下:
static normalizeUse(use, ident) {
// 单loader字符串
if (Array.isArray(use)) {
return use
// 如果是单loader情况这里会返回[[loader1...],[loader2...]]
.map((item, idx) => RuleSet.normalizeUse(item, `${ident}-${idx}`))
// 扁平化后变成[loader1,loader2]
.reduce((arr, items) => arr.concat(items), []);
}
// 对象或字符串
return [RuleSet.normalizeUseItem(use, ident)];
};
先讲解有options或者query的模式,这里会把参数包装一个对象传入normalizeUse方法:
loader && (options || query)
// indet => 'ref-'
static normalizeUseItem(item, ident) {
if (typeof item === "function")
return item;
if (typeof item === "string") {
return RuleSet.normalizeUseItemString(item);
}
const newItem = {};
if (item.options && item.query) throw new Error("Provided options and query in use");
if (!item.loader) throw new Error("No loader specified");
newItem.options = item.options || item.query;
// 防止options:null的情况
if (typeof newItem.options === "object" && newItem.options) {
// 这里只是为了处理ident参数
if (newItem.options.ident)
newItem.ident = newItem.options.ident;
else
newItem.ident = ident;
}
// 取出loader参数
const keys = Object.keys(item).filter(function(key) {
return ["options", "query"].indexOf(key) < 0;
});
keys.forEach(function(key) {
newItem[key] = item[key];
});
/*
newItem =
{
loader:'原字符串',
ident:'ref-', (或自定义)
options:{...}
}
*/
return newItem;
}
内容版权声明:除非注明,否则皆为本站原创文章。
