当前位置: 代码迷 >> 综合 >> webpack之module.rules
  详细解决方案

webpack之module.rules

热度:16   发布时间:2023-12-16 19:13:32.0

webpack中, module.rules 的默认值是一个空数组。
这个数组中的每个元素对应一个规则,这个规则可以是一个字符串,也可以是一个对象。实际应用中,往往会将其配置成一个对象。就像下面这样:

module.exports = {
    module:{
    rules:[{
    test:/\.(js|jsx)$/,include:function(content){
    return /src/.test(content);},exclude:[/node_modules/],use:{
    loader:'babel-loader',options:{
    cacheDirectory:true}}}]}
}

假设文件路径是contentPath,这条规则的意思是:
/\.(js|jsx)$/.test(contentPath) && /src/.test(contentPath) && !(/node_modules/.test(contentPath)) 返回true时,才会将该文件的代码内容交给babel-loader处理。
呃,那cacheDirectory是用来干啥的??
我们知道,babel-loader是用来将ES6转译成ES5的,但说到底,它也是个函数fn,所以转译的过程相当于执行fn.apply(context,args)
其中,args就是我们从文件中读取的代码内容,context是一个上下文对象,我们在这里配置的cacheDirectory最终会成为是context对象的的一个属性,即context.cacheDirectory,且值为true。这样,babel-loader会将转译后的结果缓存起来,下次转译时就直接从缓存中取了。

接下来我们主要看下webpack是如何将一条规则中的testincludeexclude转换成一个过滤函数,这个过滤函数又是怎么个“一夫当关万夫莫开”的。
webpack使用RuleSet类解析module.rules,这个类有个静态方法static normalizeCondition(condition),这个方法的实现如下:

const andMatcher = items => {
    return str => items.every(item => item(str));
}
const orMatcher = items => {
    return str => items.some(item => item(str));
}
const notMatcher = matcher => {
    return str=>!matcher(str);
}
function normalizeCondition(condition){
    if(typeof condition === "string"){
    return str=>condition.indexOf(str)===0;}if(typeof condition === "function"){
    return condition;}if(condition instanceof RegExp){
    return condition.test.bind(condition);}if(Array.isArray(condition)){
    const items = condition.map(c => normalizeCondition(c));return orMatcher(items);}let matchers = [];let value;Object.keys(condition).forEach(key => {
    let value = condition[key];switch(key){
    case "test":case "include":if(value){
    matchers.push(normalizeCondition(value));}break;case "exclude":if(value){
    const item = normalizeCondition(value);matchers.push(notMatcher(item));}break;default:throw new Error("Unexpected property " + key + " in condition" );}})if(matchers.length===0){
    throw new Error("Expected condition but got " + condition);}if(matchers.length===1){
    return matchers[0];}return andMatcher(matchers);
}

源码逻辑很清晰,可以看到:
一条规则中的testincludeexclude,可以配置成一个字符串、一个函数、一个正则表达式或者一个数组。如果是数组的话,会进行递归,数组元素之间是的关系(orMatcher)。

test:String | Function | RegExp | Array,
include:String | Function | RegExp | Array,
exclude:String | Function | RegExp | Array

testincludeexclude三者之间是的关系(andMatcher)。

下面是部分测试代码:

const _module = Object.create(null);
_module.exports = {
    module:{
    rules:[{
    test:/\.(js|jsx)$/,include:function(content){
    return /src/.test(content);},exclude:[/node_modules/],use:{
    loader:'babel-loader',options:{
    cacheDirectory:true}}}]}
}
const rule = _module.exports.module.rules[0];
const condition = {
    test:rule.test,include:rule.include,exclude:rule.exclude
}
const filterFn = normalizeCondition(condition);let resource = "src/index.js";
let res = filterFn(resource);
console.log(res);//返回trueresource = "index.ts";
res = filterFn(resource);//返回false
console.log(res);
  相关解决方案