细说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;
}
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/456.html