25_Webapck原理

 

Webpack源代码解析

webpack其实也就是一个函数的调用,返回一个Compile的对象,再调用Compile的run方法就可以完成项目的构建

那么我们肯定是先要从webpack这个函数去理解它在构建的过程中都做了些什么

 

 如果我们没有传入callback那么他就会执行else中的代码,首先是create函数

 

 那么我们核心的代码就在createCompiler函数中

 

 插件的执行是贯穿于webpack的整个生命周期的,webpack当中很多的东西其都是插件,比如entry,他会把它转成插件

转换的过程就在WebapackOptionsApply当中

 

 

 

 它注册插件的目的就是将compiler对象传入插件的apply函数中去,在apply函数中监听compiler对象的hooks,那么在webpack执行到某一个生命周期的时候compiler会去回调hooks

那么我们再看看hooks是什么东西

我们肯定先看打开Compiler这个类

 

 你会发现有很多的hooks(钩子),实际上他们是用了一个tapable的库有兴趣的可以去看

我们的插件都会去调用它的apply传入compiler,apply的函数中都会去执行compiler.hooks.xxx(钩子),如其中一个hooks.xxx.tap('xxx',回调)这个注册的事件会在webpack编译的某个生命周期里面compiler.hook.xxx.call('xxx')去回调

 那么我们真正构建的时候是去调用compiler的run方法

接下来分析run方法做了什么事情

 

 

 

 编译的过程在this.compile(onCompiled)中,onCompiled是没有错误的回调函数

 

 

 

 

Compiler和Compilation的区别
 Compiler:在webpack构建的之初就会创建的一个对象, 并且在webpack的整个生命周期都会存在

Compilation是到准备编译模块(比如main.js), 才会创建Compilation对象
主要是存在于 compile(之后) - make(之前) 阶段主要使用的对象

watch -> 源代码发生改变就需要重新编译模块
Compiler可以继续使用(如果我修改webpack的配置, 那么需要重新执行run run build)
Compilation需要创建一个新的Compilation对象
 
 
接下来就是Compilation对模块的处理
我们之前理解到对模块的处理是在make阶段进行的,那么我们首先一步步来分析从plugin到make阶段的过程
之前有一个WebpackOptionsApply.process的函数里面是对配置转成一个个插件的处理,那么我们从入口开始

打开apply函数

 

 它会调用EntryOptionPlugin的静态方法applyEntryOption

我们再打开applyEntryOption

打开EntryPlugin的apply方法

 

 

 那么这个hooks到make阶段的时候回调就开始执行了,并且把compilation传入

 

 

 

 

 

 打开这个_addEntryItem私有函数

 

 他的本质就是想调用addModuleTree

根据当前模块,把他加入到模块树中去

 

 处理这个模块并且把他创建

 

 最终会调用factorizeModule方法

 

 加入到队列中去

最终的执行都是按照队列的方式进行执行的

 

 他将处理好的模块传入到newModule中去

 

 看看addModule做了什么

 

 把模块加入到了modulequeue中去

当监听到某个hooks后他会去回调callback

 

 构建模块

 

 把即将构建的模块又加入到buildqueue中去了

在我们buildqueue中其实已经有很多我们加进去的模块了

而这个队列中是有一个处 理的方法的

 

具体的构造模块其实就是在这里

调用_buildModule的时候就开始真正的构建我们的模块了

 

 打开build方法

 

 其实打开的是一个子类

点击这里

 

 

 找到实现类

点开doBuild

 resource是即将要处理的资源

loaders是要应用的loaders

processResource是对资源的进一步处理

 

 processResult是之前在上面定义的函数(处理结果的函数)

 

 我们最主要的就是看它回调的这个callback

这个callback是在build函数中传入的

 

 this.parser.parse最主要的就是解析js代码,这个parser是一个类,但是是个抽象类,他的实现类是javaScriptParser,但是在处理的时候是使用了acorn库,最主要的就是分析当前模块是否依赖了其他的模块,如果依赖了,他还是会继续回到runLoader函数中去,继续去处理他所依赖的模块,依次处理

如果ast有值的话他会去处理ast,或者去调用source函数得到结果交给parsser的parse函数去处理

 

当解析完成之后他就会来到Compilation中的seal(封存)方法中

把我们解析好的模块封存到chunk中去(把我们解析好的模块分别放到哪些chunk中去)

最终解析出来的数据其实是放到compilation.assets对象中去,但是他在模块真正转成js文件之前是要进行优化的(optimization)

模块->chunk->optimization->compilation.assets

 

 有特别多的处理代码,我们一直往下翻到codeGeneration

 

 

 往下找里面有一个函数叫 createChunkAssets

往下翻

输出资源 source中有_source就是要输出的内容

目的就是将资源放到compilation对象中去

 

 this就是compilation

当我们做完这些之后就要去做我们的回调过程了

 

 这个callback是之前传入进来的,经过不断的追溯,最终是在调用seal函数的地方(Compiler的compiler方法中)

 

 他调完之后还会调用一个afterCompile的hook,afterCompile的hook调用完成之后还接着会调用callback,那么这个callback就是compile函数的参数,compile是在run方法中调用的所以我们找到run方法

 

 

 

 当我们调用完成onCompiled之后他接着就会调用emitRecords去输出里面的资源

posted @ 2022-09-13 14:47  Mr-Hou88888  阅读(30)  评论(0编辑  收藏  举报