说到webpack,相信对于前端工程师来说已经不是什么新鲜事了。但是由于webpack的配置项比较复杂灵活,给人的第一感觉是很难完全掌握。此次,我将把webpack构建过程的相关知识分享给大家,希望能帮助大家进一步了解webpack。本次分析的对象是webpack(v3.6.0),也就是gayhub的地址。因为webpack的内容太多了,一下子讲太多很容易混淆。这次先从最简单的例子说起。上升。下面是我写的一个简单的炸鸡例子://webpack.config.jsvarpath=require("path");module.exports={entry:'./src/index.js',output:{path:path.resolve(__dirname,"build"),filename:"bundle.js"}}假设我们的工作目录下有这样一个webpack.config.js文件,那么当我们执行webpack命令时【前提是你有安装webpack]后,首先会执行的是/bin目录下的webpack.js。OK,作为入口文件,我们首先要分析的是:/bin/webpack.js这个文件主要做了以下几件事:引入yargs模块,对命令行参数进行注释和重命名,添加默认参数(例如,当我们不指定--config参数时,默认会在当前目录下找到webpack.config.js文件作为配置文件)处理完参数内容后,导入lib中的webpack.js文件目录,获取编译对象编译器,然后编译(compiler.run())varwebpack=require("../lib/webpack.js");......try{//这里的选项是转换后的参数,convert-argv文件主要负责这些工作//获取编译器对象compiler=webpack(options);}catch(e){......}......//执行编译compiler.run(compilerCallback)由于这里说的例子比较简单,不涉及其他参数相关的内容,有兴趣的同学可以多了解参数处理部分,就不多解释了在这里。重点是看一下编译过程。作为complier的入口文件,我们接下来看一下:/lib/webpack.js这个文件首先调用validateSchema方法验证传入的options的格式,然后调用WebpackOptionsDefaulter实例的process方法进一步处理options(保存了两个实例属性default={},config={},分别给这两个对象附??加属性,然后挂载到options)然后实例化Compiler类。由于这个类继承自Tapable类,所以在父类上有一套实现插件的机制(applyPlugin、plugin等方法,这两个类后面会详细分析),得到编译器对象,然后执行NodeEnvironmentPlugin插件,主要是利用enhanced-resolve模块修改compiler对象,注册“before-run”回调方法,然后调用complier的apply方法,其实内部调用的是插件的apply方法,等价注册各种插件的回调方法来触发“environment”和“after-environment”。回调方法实例化WebpackOptionsApply类并调用process方法;后面会展开分析这个方法,把静态属性(各种插件方法)挂在webpack方法上,导出webpack方法。接下来我们先分析WebpackOptionsApply这个类:/lib/WebpackOptionsApply.js从上面可以看出,在编译之前,webpack会先实例化WebpackOptionsApply类,然后调用它的process方法。我们看到process方法其实注册了N多个插件,然后触发了一些插件的回调函数。首先判断options.target,如果值为"web"(本例为Mostcommon,其他情况下逻辑类似),然后注册插件JsonpTemplatePlugin【注册"this-compilation"回调】,FunctionModulePlugin【注册"compilation"回调],NodeSourcePlugin[注册“编译”和“后解析器”回调],LoaderTargetPlugin[注册“编译”回调]。注册插件LibraryTemplatePlugin【注册"编译"回调】,ExternalsPlugin【注册"编译"回调】注册插件EntryOptionPlugin【注册"entry-option"回调】触发"entry-option"回调,所以进入回调函数EntryOptionPlugin类EntryOptionPlugin插件,通过itemToPlugin方法判断是单入口文件还是多入口文件,这里以单入口为例,所以进入SingleEntryPlugin类,注册插件SingleEntryPlugin["compilation"&"make"callback】继续回到WebpackOptionsApply的process方法,然后继续通过compile.apply方法添加插件。插件太多就不一一列举了。有兴趣的可以跟踪代码了解详情,最后触发“after-plugins”和“after-resolvers”的回调函数。以上就是WebpackOptionsApply实例调用过程的全过程,过程在/bin/webpack,获取的是/lib/webpack返回的编译器对象,最后调用编译器对象的run方法。作为编译过程的核心类,我们来看看Compiler类:/lib/Compiler.js我们看到Compiler类继承自Tapable类github地址Tapable类提供了调用插件的方式。所有的webpack插件都是基于这种方式来注册和调用的。Tapable类定义了plugin方法,用于注册插件,并将插件及其回调函数以key-value的形式保存在内部_plugins={}对象中;它还定义了applyPlugins、applyPluginsWaterfall等方法来触发插件的回调函数。实际上,它是订阅-发布模型的一种实现。所以Compiler类在继承Tapable类的时候,还具有注册插件和触发回调函数的功能。接下来看Compiler中run方法首先触发的“before-run”回调函数。NodeEnvironmentPlugin插件注册回调函数,然后触发“run”回调函数。CachePlugin插件注册回调函数,调用readRecords方法()调用compile方法。输入编译过程触发“before-compile”回调函数。DllReferencePlugin注册回调函数,触发“编译”回调函数。ExternalsPlugin&DllReferencePlugin&DelegatedPlugin注册回调函数调用newCompilation方法创建Compilation实例。这个实例包含了编译过程的所有属性和方法触发“this-compilation”回调函数触发“compilation”回调函数触发“make”回调函数。如果是单入口项目,这里会触发SingleEntryPlugin插件注册的“make”回调,调用编译的addEntry方法进行模块构建。通过编译的processModuleDependencies方法收集模块依赖。最后,通过buildModule方法构建模块。调用compilation.finish()方法。调用compilation.seal()方法触发“编译后”回调函数。compile方法执行后,执行onCompiled回调触发“should”回调函数触发“done”回调函数调用emitAssets方法,触发“emit”回调函数调用emitFiles方法,触发after-emit回调函数,最后执行emitRecords方法,这是编译器run方法的主要内容分析,以上是webpack简单构建过程分析,哈哈,今天分享到这里,希望大家喜欢吧,祝大家周末愉快。。。
