前言
webpack初始化实现之后,则会通过传入的options.watch
来判断是否要开启watch,如果开启watch
则会执行watch
的流程,如果是run
,则会执行run
的流程,本系列只关注主线,所以咱们间接从run
开始,watch
感兴趣的同学能够自行钻研钻研
compiler.run()
间接看外围代码
const run = () => { this.hooks.beforeRun.callAsync(this, err => { if (err) return finalCallback(err); this.hooks.run.callAsync(this, err => { if (err) return finalCallback(err); this.readRecords(err => { if (err) return finalCallback(err); this.compile(onCompiled); }); }); });};
简略说就是做了这么几件事。
- 触发
beforeRun
的回调 - 触发
run
的回调 - 而后调
this.readRecords
- 在
readRecords
的回调里调用this.compile(onCompiled)
开启编译
咱们一步一步看beforeRun
会触发之前在NodeEnvironmentPlugin
中注册的 beforeRun 钩子,这个plugin会判断inputFileSystem
是否被配置,如果没有配置则执行purge
清理办法。
readRecords
会读取一些统计信息,因为没有配置recordsInputPath
,这里会把this.records
初始为{}
。
创立compilation实例
接下来就执行到compiler.compiler()
办法。compiler.compiler
办法贯通了整个编译过程。首先compiler
实例化了一个compilation
。
compile(callback) { const params = this.newCompilationParams(); this.hooks.beforeCompile.callAsync(params, err => { if (err) return callback(err); this.hooks.compile.call(params); const compilation = this.newCompilation(params); // do something }}
获取参数
newCompilationParams() { const params = { normalModuleFactory: this.createNormalModuleFactory(), contextModuleFactory: this.createContextModuleFactory() }; return params;}
参数有两个,一个是NormalModuleFactory
的实例,一个是ContextModuleFactory
的实例。ContextModuleFactory
这个参数我在compilation外面没搜到,暂且略过,后续打个断点看会不会走进来。这里次要看下NormalModuleFactory
。
NormalModuleFactory
先看下实例化NormalModuleFactory
的参数
const normalModuleFactory = new NormalModuleFactory({ context: this.options.context, fs: this.inputFileSystem, resolverFactory: this.resolverFactory, options: this.options.module, associatedObjectForCache: this.root, layers: this.options.experiments.layers});
留神这里的resolverFactory
, 当前会用到。
接下来看下new NormalModuleFactory
的时候产生了啥
constructor({ context, fs, resolverFactory, options, associatedObjectForCache, layers = false}) { super(); this.hooks = 定义了很多hooks this.resolverFactory = resolverFactory; this.ruleSet = ruleSetCompiler.compile([ { rules: options.defaultRules }, { rules: options.rules } ]); this.context = context || ""; this.fs = fs; this._globalParserOptions = options.parser; this._globalGeneratorOptions = options.generator; /** @type {Map<string, WeakMap<Object, TODO>>} */ this.parserCache = new Map(); /** @type {Map<string, WeakMap<Object, Generator>>} */ this.generatorCache = new Map(); /** @type {Set<Module>} */ this._restoredUnsafeCacheEntries = new Set(); const cacheParseResource = parseResource.bindCache( associatedObjectForCache ); this.hooks.factorize.tapAsync( // do something ); this.hooks.resolve.tapAsync( // dosomething );}
可能感觉太长了不看,我间接给大家翻译一下干了啥
- 定义了很多外部的hook,比方说最初注册的两个 reslover,factorize
- 定义了很多构建module须要的变量,这里先不细说。
- 同时注册了两个
NormalModuleFactory
的外部 hook。会在适合的机会在被compilation对象调用
new NormalModuleFactory()
之后,触发了compiler上的normalModuleFactory
钩子
this.hooks.normalModuleFactory.call(normalModuleFactory);
持续触发钩子回调
而后触发beforeCompile
和compile
钩子。
开始实例化
newCompilation(params) { const compilation = this.createCompilation(params); //这里简略了解为new 了一下, compilation.name = this.name; compilation.records = this.records; this.hooks.thisCompilation.call(compilation, params); this.hooks.compilation.call(compilation, params); return compilation;}
分类一下,这个函数做了两件事。
- new Compilation,再赋一点值
注册两个钩子
new Compilation 外部细节
Compilation对象示意了以后模块资源、编译生成资源、变动的文件、以及被跟踪依赖的状态信息,代表了一次资源的构建。constructor代码太多就不贴在这里了,大家能够自行去看看。
简略总结一下,就是
- 在compilation外部注册了很多外部的钩子。
- 初始化了一些本身属性
- 实例化
MainTemplate
,ChunkTemplate
,HotUpdateChunkTemplate
,RuntimeTemplate
,ModuleTemplate
。用于提供编译模板
实例化后的钩子调用
this.hooks.thisCompilation.call(compilation, params);this.hooks.compilation.call(compilation, params);
compilation
钩子的调用,会调用到之前在entryplugin注册的办法。
会往dependencyFactories里减少依赖模块。
compilation.dependencyFactories.set( EntryDependency, normalModuleFactory);
兴许你好奇,这里为什么有两个钩子?起因是跟子编译器无关。在 Compiler 的 createChildCompiler 办法里创立子编译器,其中 thisCompilation 钩子不会被复制,而 compilation 会被复制。
子编译器领有残缺的 module 和 chunk 生成,通过子编译器能够独立于父编译器执行一个外围构建流程,额定生成一些须要的 module 和 chunk。
完结
到目前为止,形容构建流程的对象compiler
和形容编译过程的对象compilation
对象曾经创立实现。下一篇文章咱们进入构建流程。