You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
compileRule=(path,rule,refs)=>{constunhandledProperties=newSet(Object.keys(rule).filter(key=>rule[key]!==undefined));/** @type {CompiledRule} */constcompiledRule={conditions: [],effects: [],rules: undefined,oneOf: undefined};//判断是否含有rules的某些参数以加入到compiledRule里this.hooks.rule.call(path,rule,unhandledProperties,compiledRule,refs);//判断key是否包含rulesif(unhandledProperties.has("rules")){unhandledProperties.delete("rules");construles=rule.rules;if(!Array.isArray(rules))throwthis.error(path,rules,"Rule.rules must be an array of rules");compiledRule.rules=this.compileRules(`${path}.rules`,rules,refs);}//判断key是否包含oneOfif(unhandledProperties.has("oneOf")){unhandledProperties.delete("oneOf");constoneOf=rule.oneOf;if(!Array.isArray(oneOf))throwthis.error(path,oneOf,"Rule.oneOf must be an array of rules");compiledRule.oneOf=this.compileRules(`${path}.oneOf`,oneOf,refs);}if(unhandledProperties.size>0){throwthis.error(path,rule,`Properties ${Array.from(unhandledProperties).join(", ")} are unknown`);}returncompiledRule;}
Webpack初始化
虽然大部分情况都在用cli或者dev-server跑webpack,它们能提供很多命令,接收参数,配置不同的npm script去跑不同的config等。但它们最终会跑以上代码,开始进行打包的工作。
webpack(config)
首先执行
const compiler = webpack(config)
webpack.js
webpack会拿到options,并且调用
createCompiler(options)
生成compiler实例并返回。getNormalizedWebpackOptions
会先处理options,传进来的options并不是拿来就用,有许多配置需要处理。applyWebpackOptionsBaseDefaults
和applyWebpackOptionsDefaults
都是给没设置的基本配置加上默认值,先执行前面的是因为需要抛出options给下面的NodeEnvironmentPlugin
使用处理完options之后就会实例化生成Compiler对象,这时候就可以往Compiler注入插件。它们会执行所有options.plugins里的apply方法,写过插件的人都知道,编写插件需要暴露apply函数,并且得到Compiler对象往compiler.hooks里注入钩子, 如果不清楚hook的用法,建议读我写的这篇文章。
最后调用
new WebpackOptionsApply().process(options, compiler)
方法,为该有的配置去注册相应的插件。初始化Compiler的工作就完成了compiler.run()
run方法里会调用一些钩子与记录信息,在这里并不重要,主要在于
this.compile(onCompiled)
,onCompiled是最终seal阶段之后的会执行的回调。生成Compilation
compile函数首先会生成params给实例化Compilation作为参数
normalModuleFactory会生成normalModule,webpack里的模块就是normalModule对象。contextModuleFactory会生成contextModule,它是为了处理(require.context引用进来的模块。
newCompilation会调用createCompilation实例化Compilation对象,并且调用钩子。
因为这时候compiler对象已经有了compilation和normalModule,所以可以传递给插件使用它们 , 或给它们的钩子注入函数实现相关功能。
在thisCompilation钩子里的插件有九个,compilation钩子甚至有四十几个,它们都是些内部插件。
thisCompilation.taps
Compilation.taps
ruleSetCompiler
在实例化normalModuleFactory的时候还会对rule进行处理,可以为之后处理模块的时候判断使用什么loader
实例化ruleSetCompiler的时候会把自己作为参数给插件用。然后调用compile,将options.rules和options.defaultRules传入进去。defaultRules是在applyWebpackOptionsDefaults的时候生成的默认rules。
RuleSetCompiler.compile会调用compileRules("ruleSet", ruleSet, refs)拼凑path并递归进行处理。
第一次调用compileRules传进来的path为
ruleSet
,ruleSet是上面包含options.rules和options.defaultRules的数组 。compileRule会递归处理所有含有rules和oneOf的嵌套对象,比如传进来的path为
rulSet[0]
,所以会取第一个对象为options.defaultRules。然后unhandledProperties会取出数组每个Object keys,options.defaultRules对象的key为'rules',所以满足unhandledProperties.has("rules")。会调用compiledRule.rules = this.compileRules(`${path}.rules`, rules, refs)
递归defaultRules数组第二次递归path为
rulSet[0].rules[0]
,然后会调用this.hooks.rule.call处理defaultRules里的每个规则。钩子会调用之前注册的BasicMatcherRulePlugin对rules的属性生成不同的conditions比如rule为
{ test: /\.js/ , use: babel-loader }
,插件new BasicMatcherRulePlugin("test", "resource")
会处理所有包含test属性的rules,会生成如下:condition就是
/\.js/
,对于之后调用exec解析js模块就会抛出babel-loader
。处理完所有的rules后,RuleSetCompiler.compile会返回如下对象之后只要执行RuleSetCompiler.exec()就能返回相对应的loader,使用方法如下
到这里,生成compilation的工作就做完了,继续Compiler的钩子流程,之后就是调用
this.hooks.make.callAsync
方法了,开始从入口构建模块。之后会有很多async hook的代码,因为是异步的原因所以会有callback hell问题,阅读起来特别恶心,而且因为async hook里可以是setTimeout,源码实现也并没有返回promise,所以也不能使用async await解决回调问题总结
以上就是一些初始化的代码,处理options,rules,注册插件,实例化normalModule,compilation对象,调用钩子传递对象给插件使用等。所有的工作做完了,会调用make hook开始后面的构建环节。
The text was updated successfully, but these errors were encountered: