细说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; }
内容版权声明:除非注明,否则皆为本站原创文章。