webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle,这是官网的介绍,我们能得到的信息就是打包、递归、构建模块,至于更多的细节则无从得知,对于我们使用来说,我们只需要掌握如何配置即可,但如果我们想自己编写插件,想学习webpack中的设计思想,那么阅读源码则是必不可少,因此我想通过阅读源码,剖析webpack工作原理,那么就让我们开始吧。(采用方式以webpack.config.js配置文件)
一、启动打包流程
1. 项目运行webpack命令
2. option配置项初始化
在cli.js中,会使用yargs.parse这个方法去解析process.argv,拿到命令行中输入的参数-p -d 这种,将拿到的参数传入到工具类中,这个工具类是专门用来获取options的,它会根据我们输入的参数,生成配置项对象,在默认不配置--config的情况下,工具类会去读取项目中根目录下webpack.config.js中的配置,然后和通过命令行参数生成的配置项对象合并,最后然后返回配置信息。
3. 创建Compiler对象
在拿到配置之后,cli.js会引入webpack这个包,执行webpack这个方法(参数为配置项options),然后:
- 校验options配置项,如果有错误则抛出
- 判断options是否是个数组,如果是数组则执行多路打包,否则执行单路打包(我这里是单路打包)
- 完善options配置:webpack中内置了一份完整默认配置,比如在没有配置文件的情况下,默认会把src/index当成入口,原因就在于默认配置中配置了entry为src/index,在我们有配置文件的情况下,webpack会将配置文件中的配置信息和内置配置合并,相同的项会以配置文件优先,这样就可以得到一份完整的配置。
- 创建Compiler对象
- 创建内置环境插件,并触发。
Compiler整个过程中只会实例一次,Compiler中有一个hooks属性,这个属性是一个对象,这个对象的属性里面包含了大量的同步和异步钩子(钩子类new 出来的实例),钩子实例用来注册和调用插件,简单点说,就是比如我把整个构建过程分成几个周期,准备、构建前,构建中,构建完成,在这个阶段我都实例好对应的钩子实例,用来注册事件函数,然后在构建周期去执行相应钩子实例上注册的函数,也就是说webpack开放钩子实例提供注册事件的能力,在准备中你要做什么,在构建前你要做什么,这些我都开放给使用者自己去注册事件去完成,这样就良好的实现了扩展性。
4. 启动构建
二、开始编译
compile方法会先调用beforeCompile钩子,执行完注册事件后再调用compile钩子,再实例一个Compilation对象,Compilation是用来负责创建bundles的,包含了一次构建中全部的资源和信息,在开发环境时,每次更改文件,都会重新创建Compilation,打包资源,最后将打包之后的内容存入到内存中。
Compilation的实例创建完成之后会,会调用一个make的钩子,进入到make的阶段,这个阶段才是真正的重头戏。。。