webpack运行过程(webpack菜鸟教程)
异步执行AsyncQueue下的_ensureProcessing()方法执行时
首先会遍历this._queued,但此时this._queued.length = 0
其次会遍历this.children,此时this.children.length = 3
this._children为三个AsyncQueue
_name为addModule的AsyncQueue, 开始它的_queued.length=0
_name为factorize的AsyncQueue, 开始它的_queued.length=入口个数
_name为build的AsyncQueue, 开始它的_queued.length=0
this.children的每一个AsyncQueue下面有一个_queued,即this.children[0]._queued
首先会处理_name是factorize的AsyncQueue
this.children[1]._queued.length=2
this.children[1]._queued是两个AsyncQueueEntry
所以执行_ensureProcessing()方法,首先会遍历 this.children[1]._queued,执行_startProcessing方法
由于AsyncQueued的this._parallelism默认是1;所以并不会两个都执行 而是执行一个入口的factorize,再执行该入口的addModule; 接着执行下一个入口的factorize,在执行addModule
factorize是分解的意思
_startProcessing()调用this.Processor,此时的Processor的name是 'bound _factorizeModule'
_ensureProcessing(entry){ this.processor(entry.item) } 复制代码
其次会处理_name是addModule的AsyncQueue
factorize和addModule的默认处理顺序是处理完一个入口的factorize和addModule,再处理下一个入口的factorize和addModule; 所有入口的factorize和addModule都处理完成后,再处理build
最后处理_name是build的AsyncQueue,_name是addModule的AsyncQueue处理完后,它的_queued.length=入口的个数
此时的Processor的name是 'bound _addModule'
name为factorize的异步队列的执行过程
Compilation类 的_factorizeModule()方法内部调用了NormalModuleFactory的create方法
function _factorizeModule(){ factory.create() } 复制代码
NormalModuleFactory类 的create()方法中触发了自己的beforeResolve钩子
NormalModuleFactory类 的beforeResolve钩子执行完成后触发了自己的factorize钩子
function create(){ this.hooks.beforeResolve.callAsync(resolveData, (err, result) => { this.hooks.factorize.callAsync(resloveData, (err, module)) }) } 复制代码
ExternalModuleFactoryPlugin 插件注册了normalModuleFactory的factorize钩子
function apply(normalModuleFactory){ normalModuleFactory.hooks.factorize.tapAsync("ExternalModuleFactoryPlugin",(data,callback)=>{ fuction handleExternal(){ callback() } handleExternal() }) } 复制代码
NormalModuleFactory自己注册了自己的factorize钩子 NormalModuleFactory的factorize钩子执行完成后触发自己的reslove钩子
this.hooks.factorize.tapAsync({}, ()=>{ this.hooks.reslove.callAsync() }) 复制代码
NormalModuleFactory自己注册了自己的reslove钩子
reslove钩子内部调用了defaultResolve()方法
defaultResolve()方法调用了resolveResource()方
resolveResource()方法调用了Resolver类的resolve()方法
resolve()方法调用了doResolve()方法
Resolver的doResolve()方法内部触发了自己的resolve钩子
ResolverCachePlugin插件注册了Resolver的resolve钩子
DescriptionFileFlugin插件注册了Resolver的resolve钩子
用来处理描述文件即package.json文件 复制代码
NextPlugin插件注册了Resolver的resolve钩子
AliasFieldPlugin插件注册了Resolver的resolve钩子
先读取package.json文件中的browser的配置 browser配置:定义npm包在browser环境下的入口文件 复制代码
ConditionalPlugin插件注册了Resolver的resolve钩子
RootsPlugin插件注册了Resolver的resolve钩子
FileExistsPlugin插件注册了Resolver的resolve钩子
const file = requet.path fs.stat(file, ) // CachedInputFileSystem文件 class CacheBackend { provide(path, options, callback){ let cacheEntry = this._data.get(paeh) if(cacheEntry !== undefined){ } this._provider.call(this._providerContext, path, (err, path) => { this._storeResult(path, err, result) }) } } //graceful-fs/polyfills.js function statFix(){ } // <node_internal>/fs.js function stat(path, options = {bigit:false}, callback){ } 复制代码
newStack = [ "resolve: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "parsedResolve: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "describedResolve: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "normalResolve: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "relative: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "describedRelative: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "rawFile: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "file: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "finalFile: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "existingFile: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js", "resolved: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js" ] 复制代码
将入口文件及其相关联文件和路径加入到AsyncQueue._queued中,然后遍历AsyncQueue._queued
AsyncQueue._queued = [ "D:\\code\\web_learn\\webpack\\demo\\src\\app.js", "D:\\code\\web_learn\\webpack\\demo\\src", "D:\\code\\web_learn\\webpack\\demo", "D:\\code\\web_learn\\webpack", "D:\\code\\web_learn", "D:\\code", "D:\\", "D:\\code\\web_learn\\webpack\\demo\\package.json", "D:\\code\\web_learn\\webpack\\demo\\src\\search.js", ] 复制代码
name为addModule的异步队列的执行过程
_startProcessing(entry){ this._processor(entry.item, (e,r) => { this._handleResult(entry, e, r) }) } 复制代码
调用Compilation的_addModule()
// module大致的样子 module = { rawRequest: './src/app.js', request: 'D:\\code\\web_learn\\webpack\\demo\\src\\app.js', resource: 'D:\\code\\web_learn\\webpack\\demo\\src\\app.js', userRequest: 'D:\\code\\web_learn\\webpack\\demo\\src\\app.js', type: 'javascript/auto' } function _addModule(module, callback) { const identifier = module.identifier //判断是否已经添加 const alreadyAddedModule = this._modules.get(identifier) if(alreadyAddedModule){ return callback(null, alreadyAddedModule) } // 从缓存中读取 this.modulesCache.get(identifier, null, (err, cacheModule) => { if(cacheModule) { cacheModule.updateCacheModule(module) module = cacheModule } this._modules.set(identifier, module) this.modules.add(module) callback(null,module) // 执行_handleResult }) } 复制代码
执行AsyncQueue类中的_handleResult()
执行Compilation下面的handleModuleCreation下面的this.factorizeModule下面的 addModule(newModule)
执行Compilation下面的_handleModuleBuildAndDependencies 下面的 this.buildModule
Compilation的buildQueue新增newModule:this.buildQueue.add(module, callback)
接着将其他的module添加到buildQueue中
所有module加入到buildQueue后,name为build的AsyncQueued的_queued.length = 2
所以接着遍历这个_name为build的AsyncQueue的_queued
name为build 的异步队列的执行过程
此时_this.processer为 bound _buildModule
执行Compilation类下的_buildModule()
首先判断该module是否需要build
_buildModule(module, callback) { module.needBuild({}, (err, needBuild) => { if(needBuild){ this.hooks.buildModule.call(module) this.buildModules.add(module) module.build() } }) } 复制代码
开始构建module
// NormalModule.js function build(){ this._doBuild() } _doBuild(){ }
作者:yanessa_yu
链接:https://juejin.cn/post/7034797921027489829