webpack之module.rules

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);//返回true

resource = "index.ts";
res = filterFn(resource);//返回false
console.log(res);

猜你喜欢

转载自blog.csdn.net/qzw752890913/article/details/105684574