1. 什么是webpack
webpack
是一个模块化打包工具,它将一切文件都视为模块,通过loader
编译转换文件,通过plugin
注入钩子,最后将输出的资源模块组合成文件。
它的主要的配置信息有entry
、output
、modules
、plugins
2. 构建流程
基础概念
Compiler
:Webpack
的运行入口,实例化时定义webpack
构建主要流程,同时创建构建时使用的核心对象compilation
Compilation
: 由Compiler
实例化,存储构建过程中流程使用到的数据,用户控制这些数据的变化,每一次构建创建一个Compilation
实例Chunk
:一般一个入口对应一个Chunk
Module
:用于表示代码模块的类型,有很多子类用于处理不同情况的模块,模块相关信息都可以从Module
实例中获取,例如dependiencies
记录模块的依赖信息Parser
:基于acorn
来分析AST
语法树,解析出代码模块的依赖Dependency
:解析时用户保存代码模块对应的依赖使用的对象Template
: 生成最终代码要使用到的代码模块
基本流程
- 创建
Compiler
实例,用于控制构建流程,compiler
实例包含webpack
基本环境信息 - 根据配置项转换成对应内部插件,并初始化
options
配置项 - 执行
compiler.run
- 创建
Compiltation
实例,每次构建都会新创建一个Compiltation
实例,包含了这次构建的基本信息 - 从
entry
开始递归分析依赖,对每个依赖模块进行buildModule
,通过Loader
将不同类型的模块转换成Webpack
模块 - 调用
Parser.parse
将上面的结果转换成AST
树 - 遍历
AST
树,收集依赖dependency
,并保存在compilation
实例的dependiencies
属性中 - 生成
chunks
,不同entry
生成不同chunk
,动态导入也会生成自己的chunk
,生成chunk
后还会进行优化 - 使用
template
基于compilation
的数据生成结果代码
编译过程
- 第一步: 先初始化参数,通过
yargs
将webpack.config.js
和shell
脚本的配置信息合并,进行参数的初始化; - 第二步:利用初始化的参数创建
complier
对象,complier
可以视为一个webpack
的实例,存在于webpack
从启动到结束的整个过程,他包含了webpack
的module
、plugin
等参数信息,然后调用complier.run
方法开始编译。 - 第三步:根据
entry
信息找到入口文件,创建compilation
对象,可以理解为webpack
一次编译的过程,包含了当前编译环境的所有资源,包括编译后的文件。 - 第四步:通过配置信息,调用
loader
进行模块翻译,使用acorn
将模块转换为AST
,当遇到require
依赖时,创建依赖并加入依赖数组,再找出依赖的依赖,递归处理所有的依赖。 - 第五步:完成第四步后将得到所有模块的依赖关系和模块翻译后的文件,然后调用
compilation.seal
方法,对这些模块和根据模块依赖关系创建的chunk
进行整理,将所有资源进行合并拆分等操作。这是最后一次能修改输出内容的地方。 - 第六步:根据配置信息中的
output
配置,进行最后模块的文件输出,指定输出文件名和文件路径。
3. 原理
webpack
打包输出后的文件其实就是一个闭包,传入的参数是一个对象,键值为所有输出文件的路径,内容为eval
包裹的文件内容;闭包内重写了模块的加载方式,自己定义了__webpack_require__
方法,来实现模拟的commonjs
规范模块加载机制。
webpack
实际上是基于事件流的,通过一系列的插件来运行。webpack
利用tapable
库提供各种钩子来实现对于整个构建流程各个步骤的控制。