webpack源码之run方法(创建模块对象逻辑)

前言

上篇文章是webpack执行逻辑即Compiler对象的生成,本文紧接着webpack函数之后的逻辑,主要是Compiler对象的run方法的执行逻辑。

Run方法执行前

在执行run方法执行前,webpack函数执行前还有一些其他重要的逻辑,也是之后会一一说明的这里暂不展开说明。

progress参数支持

该参数是用于打印编译的进度,实际上是创建/lib/ProgressPlugin插件对象,并调用compiler.apply方法来执行ProgressPlugin的apply方法。

watch相关

监听相关配置,如果需要监听文件则需要配置watch相关参数等,最主要的是开启watch后最后会调用Compiler对象的watch方法。

Run方法执行逻辑

调用Compiler的实例方法run,开启整个的编译过程。下面是run实例方法的主要执行逻辑图:
在这里插入图片描述
从上面逻辑可以看出整个执行顺序,这里需要注意的是:

run事件执行逻辑包含在before-run的回调函数中

this.applyPluginAsync('before-run', this, err => {
	// 其它逻辑
	this.applyPluginAsync('run', this, err => {
		// 其它逻辑
		this.compile(onCompiled)
	})
})

这里需要注意的是applyPluginAsync,实际上该函数是Tapable类中的实例方法,主要的功能按照队列形式批量调用指定的事件。

compile实例方法执行

run事件对应的回调函数中主要是执行compile实例方法,主要的逻辑执行如下:
在这里插入图片描述
首先,newCompilationParams方法执行,该方法是用于生成Compilation对象需要的相关参数,具体是:

  • normalModuleFactory

  • contextModuleFactory

  • compilationDependencies
    webpack能够解析三种文件路径:绝对路径、相对路径、模块路径,文件路径的解析依赖于resolver。webpack中有三种内置类型的resolver,其中两种如下:

  • Normal:通过绝对路径或相对路径,解析一个模块

  • Context:通过给定的 context 解析一个模块
    这里的normalModuleFactory和contextModuleFactory就是对应相应类型的resolver解析处理的模块工厂,例如normalModuleFactory是创建normalModule的。

其次,before-compile事件执行,这里主要的逻辑点是:

  • newCompilation:创建一个Compilation对象
  • make事件的执行
Compilation对象创建

Compilation构造函数中初始化相关的实例属性,这里需要主要关注1个属性的初始化过程:

  • mainTemplate

    注册一系列的事件:startup、render、local-vars、require、module-obj、require-extensions
    实际上该属性对应的mainTemplate对象是定义__webpack_require__相关的最后输出文件的代码

主要注意的是mainTemplate类继承自Template,而Template继承了Tapable。

this-compilation事件

执行this-compilation事件,依据本系列的简单实例的执行逻辑,之前注册了this-compilation只有webpack函数执行过程中的JsonpTemplatePlugin注册了,具体逻辑如下:

compiler.plugin("this-compilation", (compilation) => {
	compilation.mainTemplate.apply(
		new JsonpMainTemplatePlugin()
	);
	compilation.chunkTemplate.apply(
		new JsonpChunkTemplatePlugin()
	);
	compilation.hotUpdateChunkTemplate.apply(
		new JsonpHotUpdateChunkTemplatePlugin()
	);
});

mainTemplate等继承了Tapable了,所以mainTemplate.apply就是调用Tapable中的apply实例方法,即调用对应插件的apply方法。这里依次调用了JsonpMainTemplatePlugin、JsonpChunkTemplatePlugin、JsonpHotUpdateChunkTemplatePlugin对应的apply方法,实际上这些插件的apply逻辑也是注册相关的事件,具体有:

  • local-vars
  • jsonp-script
  • require-ensure
  • require-extensions
  • bootstrap
  • hot-bootstrap
  • hash
  • render
compilation事件

compilation事件的处理函数比较多,主要的内容是注册相应的事件以及dependencyFactories、dependencyTemplates添加相应值。其中事件具有有:

  • render
  • package
  • hash
  • parser
  • normal-module-loader
  • after-resolve
  • alternatives
  • optimize-chunks-basic
  • optimize-extracted-chunks-basic
  • finish-modules
  • asset-path
  • global-hash
  • hash-for-chunk
  • record-modules
  • revive-modules
  • record-chunks
  • revive-chunks
  • seal
applyPluginsParallel(‘make’, callback)

执行make事件,会找到在webpack函数执行过程中注册的make:

 compiler.plugin("make", (compilation, callback) => {
     const dep = SingleEntryPlugin.createDependency(this.entry, this.name);
     compilation.addEntry(this.context, dep, this.name, callback);
})

调用Compilation的addEntry实例方法,由此从入口开始解析模块、收集依赖等操作。
主要的逻辑流程如下:

Compilation对象addEntry -> _addModuleChain -> 找到对应normalModule类型的moduleFactory -> 调用moduleFactory的create方法

这里需要注意的点是:

  • 找到对应normalModule类型的moduleFactory,实际上会在对应的dependencyFactories属性中查找对应具体类型的moduleFactory
  • dependencyFactories是map结构,key是dependency对应的构造函数,value就是对应的moduleFactory了
  • create方法存在回调函数,该回调函数就是产生一个Module对象后相关的处理逻辑,需要重点关注

由于分析源码的实例是单入口的,所以这里对应着SingleEntryDependency的值,即NormalModuleFactory。
NormalModuleFactory中create方法执行逻辑如下:
在这里插入图片描述
上面逻辑中需要注意的三点:

  • applyPluginsAsyncWaterfall(‘before-resolve’)

    执行对应before-resolve事件,执行开始模块解析前相关逻辑

  • this.applyPluginsWaterfall0(“factory”, null)

    执行对应的factory事件,这里需要提及的是factory是在对应的ModuleFactory中构造函数中注册,例如NormalModuleFactory中

  • resolver函数执行

    this.applyPluginsWaterfall0(“resolver”, null)执行对应的resolver事件,该事件也是在NormalModuleFactory的构造函数中注册的

这里可以知道resolver就是用来解析模块的,当解析后执行回调函数逻辑,这里需要关注回调逻辑中的NormalModule对象的创建,即模块对象。

createdModule = new NormalModule(
	result.request,
	result.userRequest,
	result.rawRequest,
	result.loaders,
	result.resource,
	result.parser
);

当创建了对应的module对象,最后执行逻辑还是回到最初的moduleFactory.create的回调函数这里(其中关于resolver相关的逻辑之后会具体细看,这里先看整体执行逻辑)。
moduleFactory.create的回调函数中主要逻辑有三点:

  • addModule:添加模块到指定地方
  • onModule:entry对应模块赋值操作
  • buildModule:编译模块

当整体逻辑执行到这里,实际上webpack之后要做的内容就是:

分析模块对象对应的模块的内容并进行优化,即buildModule之后的内容了,这部分内容比较重要也相对复杂,会单独一篇

总结

当Compilation调用run方法后,实际上整个的执行流程主要是:

  • run方法执行,before-run和run对应事件执行
  • 调用compile实例方法,创建对应的Compilation对象,其中会执行this-compilation和compilation事件对应注册相应的事件以及依赖相关的赋值
  • 执行make事件
  • 调用addEntry开始模块编译前相关解析工作
  • 调用_addModuleChain来构建链式结构
  • moduleFactory.create开始生产Module模块对象,生成后执行其回调开始编译模块
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值