目的:了解输入打包命令后发生了什么事情
本质:Node去运行一个js文件,这个js文件做的事情就是铺垫好流程,接着启动打包流程。
首先我们先来了解一下这个js文件到底有什么东西,再来引出概念。
我把这个文件形容为一个车间,那么车间最重要的是什么呢,最重要的是要有机床。
这个机床在webpack构建中称之为Compiler。它是一个编译类。
那么这个机床要需要启动的话要先准备什么,需要先输入它该怎么运行的参数。
这个参数就是我们编写的webpack.config.js配置文件。也还需要其他shell配置。
输入完参数,接着我们需要在机床上安装一些机械手去控制零件变化,这些机械手就是它的插件。称为Plugin。
加载完插件后,机床(编译器Compiler)就可以开始工作了。
这个在webpack整个核心的打包核心阶段称之为初始化阶段。
即
1.创建编译器对象(new Compiler());
2.初始化参数(options);
3.初始化编译环境(加载插件Plugin);**
4.开始编译(compilere.run);**
那这个编译器怎么工作的。
首先这个车床它之前已经准备好了参数和设备,那么现在就该有某个东西推着这些零件往前走,这个东西就是滚动带。在webpack里面叫Compilation。它代表了单次构建过程。由它来推动着打包过程。
它是如何推动这个过程呢?
首先我们需要确定好入口处在哪里,然后从这里开始加载,目标就是生成一个入口模块对象。
在生成模块过程中需要将有些零件转换成可加工的形式,由于在webpack只能识别js文件,所以我们在构建过程中把其他资源文件例如css,sass,png等格式的文件进行处理转换成可加工的形式。这个过程需要用到的就是Loader(加载器)。Loader能将这些资源文件进行处理解析,成为可被进行处理的形式。这些加载器是从哪里来的呢,就是我们在一开始初始化参数时定义的。Compilation会从编译器那边拿到这些loader的信息进行处理最后将模块转义成标准的js内容。
接着这些零件可以处理了,但是杂乱无章的零件让机器不好处理,我们需要将这些零件都联系到一起。(即找到它们所有的依赖关系)但想要找到这个零件需要用到哪个零件进行组件都不知道从哪看起。这时我们就需要先让零件序列化,能按图索骥的去操作它。用到了babel/paser将它们解析成AST对象。
稍微解释一下AST,它叫做抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示。简而言之,它可以表示源代码中的每一个结构。
例如:
有了Ast对象,现在就可以获取这个模块对应的依赖。
怎么获取这个模块对应的依赖呢?
babel/traverse这个工具可以通过import/require语句来进行判断。这时找到入口文件所需要的依赖之后注入到依赖数组中,生成一个含有文件名,ast对象,依赖数组的入口模块。
接着在重复上述步骤递归去找到入口模块下的依赖对应的依赖。这时将所有的零件都联系起来。
展开说一下找寻依赖关系的步骤,假如入口文件的依赖关系如下:
经过加工后形成入口模块流程如下:
这时compliation会依次去遍历这两个依赖文件,生成对应的模板:
由于a.js文件下仍有依赖文件,所以compliation会继续遍历,直到没有新的依赖为止:
这个阶段在webpack整个核心的打包核心阶段称之为构建阶段。
1.编译模块(make);loader解析,生成ast对象,构建入口模块。
2.完成模块编译;找到入口模块下的所有依赖关系,生成不同模块。
此时我们把一个个零件加工好了,也把它们之间的关系标明了,最后就是要将它们包装起来。这时需要用的包装纸包装成小成品,在webpack里面叫做chunk。按照一定的规则分成一个个chunk,一个chunk可以包含一个模块或者多个模块。将一个个chunk添加到输出列表中去。最后调用node的文件流(fs),根据配置好的出口路径和文件名,把文件写到文件系统中去生成一个js打包文件。
这个阶段在webpack整个核心的打包核心阶段称之为生成阶段。
即
1.输入资源(seal);根据依赖关系生成一个个chunk,添加到输出列表。
2.写入文件系统;根据配置出口路径和文件名,进行写入。
整体的文件形态流转:
总结
webpack基本的构建流程大体上如上述所示,但是还有涉及的很多细节无法进行逐一展开,但理解了大概的流程会对webpack有一个新的认识,它之所强大是因为这条流程基本是不变的,而且拓展性强,它利用loader,plugin插件来不断壮大它的生态,成为了前端一个不那么容易被替代的构建工具。