当前位置: 首页 > Web前端 > JavaScript

webpack流程分析(三)创建编译对象

时间:2023-03-27 12:25:53 JavaScript

前言webpack初始化完成后,会通过传入的options.watch判断是否开启手表。如果watch被打开,watch进程就会被执行。如果是run的话,就是执行run的过程,本系列只关注主线,所以我们直接从run开始,对watch感兴趣的同学可以研究一下compiler.run(),直接看core代码construn=()=>{this.hooks.beforeRun。callAsync(this,err=>{if(err)returnfinalCallback(err);this.hooks.run.callAsync(this,err=>{if(err)returnfinalCallback(err);this.readRecords(err=>{如果(错误)返回finalCallback(错误);this.compile(onCompiled);});});});};触发beforeRun的回调触发run的回调,然后调用this.readRecords,在readRecords的回调中调用this.compile(onCompiled)开始编译。一步一步来看,beforeRun会触发之前在NodeEnvironmentPlugin中注册的beforeRunhook。本插件会判断inputFileSystem是否为Configuration,如果没有配置则执行purge清理方法。readRecords会读取一些统计信息。由于没有配置recordsInputPath,这里this.records会被初始化为{}。创建编译实例,然后执行compiler.compiler()方法。compiler.compiler方法贯穿整个编译过程。首先,编译器实例化一个编译。编译(回调){constparams=this.newCompilationParams();this.hooks.beforeCompile.callAsync(params,err=>{if(err)returncallback(err);this.hooks.compile.call(params);constcompilation=this.newCompilation(params);//做点什么}}getparametersnewCompilationParams(){constparams={normalModuleFactory:this.createNormalModuleFactory(),contextModuleFactory:this.createContextModuleFactory()};returnparams;}有两个参数,一个是NormalModuleFactory的实例,一个是实例ContextModuleFactory的,在编译的时候没有找到参数ContextModuleFactory,所以先跳过,后面打个断点看看会不会进来。这里主要看NormalModuleFactory。NormalModuleFactory先看实例化NormalModuleFactory的参数constnormalModuleFactory=newNormalModuleFactory({context:this.options.context,fs:this.inputFileSystem,resolverFactory:this.resolverFactory,options:this.options.module,associatedObjectForCache:this.root,图层:this.options.experiments.layers});注意这里的resolverFactory,后面会用到。接下来看下面newNormalModuleFactory的时候生成了啥constructor({context,fs,resolverFactory,options,associatedObjectForCache,layers=false}){super();this.hooks=定义了很多hooksthis.resolverFactory=resolverFactory;this.ruleSet=ruleSetCompiler.compile([{rules:options.defaultRules},{rules:options.rules}]);this.context=上下文||"";这个.fs=fs;this._globalParserOptions=options.parser;this._globalGeneratorOptions=options.generator;/**@type{Map>}*/this.parserCache=newMap();/**@type{Map>}*/this.generatorCache=newMap();/**@type{Set}*/this._restoredUnsafeCacheEntries=newSet();constcacheParseResource=parseResource.bindCache(associatedObjectForCache);这个钩子s.factorize.tapAsync(//做点什么);this.hooks.resolve.tapAsync(//dosomething);}可能读起来太长了,我就给大家翻译一下吧,定义了很多内部hook,比如最后注册的两个reslover,factorize定义了很多构建模块所需的变量,这里不赘述,同时注册NormalModuleFactory的两个内部hook。适时,编译对象调用newNormalModuleFactory()后,触发编译器上的normalModuleFactoryhookthis.hooks.normalModuleFactory.call(normalModuleFactory);继续触发钩子回调,然后触发beforeCompile和compile钩子。开始实例化newCompilation(params){constcompilation=this.createCompilation(params);//这里简单理解为new,compilation.name=this.name;compilation.records=this.records;this.hooks.this编译。呼叫(编译,参数);this.hooks.compilation.call(编译,参数);returncompilation;}分类,这个函数做了两件事。newCompilation,赋一点值注册两个hooksnewCompilation内部细节Compilation对象代表当前模块资源,编译生成资源,变化文件,跟踪依赖的状态信息,代表一次资源构建。构造函数代码太多就不贴了,大家可以自行查看。简单总结一下,编译内部注册了很多内部钩子。一些自属性被初始化以实例化MainTemplate、ChunkTemplate、HotUpdateChunkTemplate、RuntimeTemplate和ModuleTemplate。This.hooks.thisCompilation.call(编译,参数);this.hooks.compilation.call(编译,参数);compilationhook的调用会调用在entryplugin中注册的before方法。依赖模块将添加到dependencyFactories。compilation.dependencyFactories.set(EntryDependency,normalModuleFactory);也许你很好奇,这里为什么会有两个钩子?原因与子编译器有关。在Compiler的createChildCompiler方法中创建子编译器,这里不会复制thisCompilationhook,但会复制compilation。子编译器具有完整的模块和块生成,子编译器可以独立于父编译器执行核心构建过程,另外生成一些需要的模块和块。结束至此,描述构建过程的对象编译器和描述编译过程的对象编译对象已经创建完成。在下一篇文章中,我们将进入构建过程。

最新推荐
猜你喜欢