webpack中关于config中配置的module.rules的loader的加载和传递流程

发布于:2023-01-13 ⋅ 阅读:(424) ⋅ 点赞:(0)

上一篇介绍到的内容是刚刚进入webpack的Complier的过程,大概说明了在Complier中包含了

const isSorted = array => {}
const sortObject = (obj, keys) => {}
class Compiler {}
module.exports = Compiler;

并且大致说明了一下tapable中对于钩子的应用的基本原理。另外附上了Complier的基本结构脑图如下:
在这里插入图片描述
上述内容是对上一篇内容的总结,接下来继续往下研究Complier对应的编译过程。还是那个问题,要看看它对于Loader的解析过程是怎么样的。

在webpack.js中的createCompiler方法下:

const createCompiler = rawOptions => {
	const options = getNormalizedWebpackOptions(rawOptions);
	applyWebpackOptionsBaseDefaults(options);
	const compiler = new Compiler(options.context, options); //创建Compiler对象
	new NodeEnvironmentPlugin({
		infrastructureLogging: options.infrastructureLogging
	}).apply(compiler);
	if (Array.isArray(options.plugins)) {
		for (const plugin of options.plugins) {
			if (typeof plugin === "function") {
				plugin.call(compiler, compiler);
			} else {
				plugin.apply(compiler); //调用CLIPlugin的apply方法
			}
		}
	}
	applyWebpackOptionsDefaults(options);
	compiler.hooks.environment.call();
	compiler.hooks.afterEnvironment.call();
	new WebpackOptionsApply().process(options, compiler);
	compiler.hooks.initialize.call();
	return compiler;
};

在这里插入图片描述
在这里插入图片描述
下图可以看到它的rules的值,就是webpack.config.js中定义的内容,如下:
在这里插入图片描述使用map循环遍历,得到一个新的数组。
以CompileRule作为循环遍历的方法体进行判断,如下:
在这里插入图片描述其中Object.keys(rule)的值如下:

在这里插入图片描述它对应于webpack.config.js中的

在这里插入图片描述

//node_modules/webpack/lib/rules/RuleSetCompiler.js
compileRule(path, rule, refs) {
		const unhandledProperties = new Set(
			Object.keys(rule).filter(key => rule[key] !== undefined)\
        	//Object.keys遍历所有的属性
        	//filter过滤ruls的属性
        	//如果对应key的值不为空,则返回给Set
        	//最后生成一个Set对象
		);

通过使用Set对象进行重构,得到unhandledProperties(直译过来是:未经处理的属性),如下:
在这里插入图片描述在这里插入图片描述
可以通过Set的keys方法来看它包含的条目,如下:

在这里插入图片描述
紧接着调用this.hooks.rule.call:
在这里插入图片描述
这个可能会引起困扰,因为它也被命名为 rule,可是考虑上下文环境,hooks下的rule是区别于unhandledProperties对应的rule的。hooks下的rule对应于RuleSetComplier中的构造器中对于hooks的定义,如下:

在这里插入图片描述

很明显,它是tapable中的SyncHook,也就是一个同步钩子。其中参数包括 path、rule、unhandledProperties、compiledRule和references。

调用钩子,执行call的时候,会出现如下匿名函数,这个在上一篇tapable的介绍中有相关的说明:

(function anonymous(path, rule, unhandledProperties, compiledRule, references
) {
"use strict";
var _context;
var _x = this._x;
var _fn0 = _x[0];
_fn0(path, rule, unhandledProperties, compiledRule, references);
var _fn1 = _x[1];
_fn1(path, rule, unhandledProperties, compiledRule, references);
var _fn2 = _x[2];
_fn2(path, rule, unhandledProperties, compiledRule, references);
var _fn3 = _x[3];
_fn3(path, rule, unhandledProperties, compiledRule, references);
var _fn4 = _x[4];
_fn4(path, rule, unhandledProperties, compiledRule, references);
var _fn5 = _x[5];
_fn5(path, rule, unhandledProperties, compiledRule, references);
var _fn6 = _x[6];
_fn6(path, rule, unhandledProperties, compiledRule, references);
var _fn7 = _x[7];
_fn7(path, rule, unhandledProperties, compiledRule, references);
var _fn8 = _x[8];
_fn8(path, rule, unhandledProperties, compiledRule, references);
var _fn9 = _x[9];
_fn9(path, rule, unhandledProperties, compiledRule, references);
var _fn10 = _x[10];
_fn10(path, rule, unhandledProperties, compiledRule, references);
var _fn11 = _x[11];
_fn11(path, rule, unhandledProperties, compiledRule, references);
var _fn12 = _x[12];
_fn12(path, rule, unhandledProperties, compiledRule, references);
var _fn13 = _x[13];
_fn13(path, rule, unhandledProperties, compiledRule, references);
var _fn14 = _x[14];
_fn14(path, rule, unhandledProperties, compiledRule, references);
var _fn15 = _x[15];
_fn15(path, rule, unhandledProperties, compiledRule, references);
var _fn16 = _x[16];
_fn16(path, rule, unhandledProperties, compiledRule, references);
var _fn17 = _x[17];
_fn17(path, rule, unhandledProperties, compiledRule, references);
var _fn18 = _x[18];
_fn18(path, rule, unhandledProperties, compiledRule, references);
var _fn19 = _x[19];
_fn19(path, rule, unhandledProperties, compiledRule, references);
var _fn20 = _x[20];
_fn20(path, rule, unhandledProperties, compiledRule, references);
var _fn21 = _x[21];
_fn21(path, rule, unhandledProperties, compiledRule, references);

})

其中对应_fn0的内容如下:

(path, rule, unhandledProperties, result) => {
  if (unhandledProperties.has(this.ruleProperty)) {
  	unhandledProperties.delete(this.ruleProperty);
  	const value = rule[this.ruleProperty];
  	const condition = ruleSetCompiler.compileCondition(
  		`${path}.${this.ruleProperty}`,
  		value
  	);
  	const fn = condition.fn;
  	result.conditions.push({
  		property: this.dataProperty,
  		matchWhenEmpty: this.invert
  			? !condition.matchWhenEmpty
  			: condition.matchWhenEmpty,
  		fn: this.invert ? v => !fn(v) : fn
  	});
  }
}

再往下会发现,它对应如下内容:
在这里插入图片描述到这一步这个流程就和在构造过程中对于钩子的注册串起来了。

这其中的this.ruleProperty的ruleProperty来自于哪儿?

/**
	 * @param {RuleSetCompiler} ruleSetCompiler the rule set compiler
	 * @returns {void}
	 */
	apply(ruleSetCompiler) {
		ruleSetCompiler.hooks.rule.tap(
			"BasicMatcherRulePlugin",
			(path, rule, unhandledProperties, result) => {
                	//如果未经处理的属性中包含 this.ruleProperty
				if (unhandledProperties.has(this.ruleProperty)) {
                    //在unhandleProperties的Set集合中删掉这个 ruleProperty
					unhandledProperties.delete(this.ruleProperty);
					const value = rule[this.ruleProperty]; //获取rule中对应于this.ruleProperty的值,对于test来说就是 /\\.css$/
                    //调用compileCondition
                    //当前对于webpack.config.js中的配置来说,第一个参数:"ruleSet[1].rules[0].test",第二个参数是: /\\.css$/
                    //在compileCondition中找到对应于正则表达式的分支判断,并得到对应的返回结果
					const condition = ruleSetCompiler.compileCondition(
						`${path}.${this.ruleProperty}`,
						value
					);
					const fn = condition.fn;//根据正则表达式得到一个对应于正则匹配的函数
					//当前上下文环境对应的 this.dataProperty是resource
                    //this.invert是false
                    //machWhenEmpty在this.invert为false的情况下取冒号后面的内容,也就是上面condition返回的matchWhenEmpty
                    //fn对应于fn
					result.conditions.push({
						property: this.dataProperty,
						matchWhenEmpty: this.invert
							? !condition.matchWhenEmpty
							: condition.matchWhenEmpty,
						fn: this.invert ? v => !fn(v) : fn
					});
				}
			}
		);
	}


//node_modules/webpack/lib/rules/RuleSetCompiler.js
//RuleSetCompiler
compileCondition(path, condition) {
    ...
		if (condition instanceof RegExp) {
			return {
				matchWhenEmpty: condition.test(""),
				fn: v => typeof v === "string" && condition.test(v)
			};
		}    
}

这一过程完成后 this.hooks.rule.call中每个参数的对应结果如下:

在这里插入图片描述
这一系列完成之后回到 node_modules/webpack/lib/rules/RuleSetCompiler.js 下的 compile:如下:
在这里插入图片描述
其中rules对于的结果为:
在这里插入图片描述
当调用return对象中的exec的属性的情况下,才会执行相应的规则。

到这一步才算是根据webpack.confg.js中的module.rules下的Loader规则生成了对应的ruleSet,也就是下图标注的位置:

在这里插入图片描述
既然在ruleSet中定义了exec,那就必然有调用,ruleSet.exec,调用的位置在

在这里插入图片描述在这里插入图片描述当resource文件找到index.css的部分的时候,会执行上述规则,调用exec并且返回响应的effects,如下:
在这里插入图片描述然后再useLoaders中添加对应的返回的effects内容:

在这里插入图片描述然后useLoaders传递给NormalModuleFactory下的resolveRequestArray处理:
在这里插入图片描述下一篇讲Loader的编译和bundle.js的输出。

附件:示例代码

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到