tags: [组件]
categories: 底层原理及基础


流程概括

  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
  • 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,通过执行对象的 run 方法开始执行编译
  • 确定入口:根据配置中的 entry 找出所有入口文件
  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容及它们之间的依赖关系
  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk, 再将每个 Chunk 转换成一个单独的文件加入输出列表中,这是可以修改输出内容后的最后机会
  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,将文件的内容写入到文件系统中

流程细节

初始化

启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler

事件 解释
初始化参数 从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。在这个过程中还会执行配置文件中的插件实例化语句 new Plugin()
实例化 Compiler 用上一步得到的参数初始化 Compiler 实例,Compiler 负责文件监听和启动编译。在Compiler 实例中包含了完整的 webpack 配置,全局只有一个 Compiler 实例
加载插件 依次调用插件的 apply 方法,让插件可以监听后续的所有事件节点。同时向插件传入 compiler 实例的引用,以方便插件通过 compiler 调用 webpack 提供的 API
environment 开始应用 Node.js 风格的文件系统到 compiler 对象,以方便后续的文件寻找和读取
entry-option 读取配置的Entrys,为每个 Entry 实例化一个对应的 EntryPlugin,为后面该 Entry 的递归解析工作做准备
after-plugins 调用完所有内置的和配置的插件的 apply 方法
after-resolvers 根据配置初始化 resolver, resolver 负责在文件系统中寻找指定路径的文件

编译

从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module, 递归地进行编译处理

事件 解释
run 启动一次新的编译
watch-run 和 run 类似,区别在于它是在监听模式下启动编译,在这个事件中可以获取是哪些文件发生了变化从而导致重新启动一次新的编译
compile 该事件是为了告诉插件一次新的编译将要启动,同时会给插件带上 compiler 对象
compilation 当webpack 以开发模式运行时,每当检测到文件的变化,便有一次新的 compilation 被创建。一个 Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。Compilation 对象也提供了很多事件回调给插件进行拓展
- build-module: 使用对应的 Loader 去转换一个模块


- normal-module-loader: 在用 Loader 转换完一个模块后,使用 acorn 解析转换后的内容,输出对应的抽象语法树(AST),以方便 Webpack 在后面对代码进行分析
- program: c
| | make | 一个新的 Compilation 创建完毕,即将从 Entry 开始读取文件,根据文件的类型和配置的 Loader 对文件进行编译,编译完后再找出该文件依赖的文件,递归地编译和解析 | | after-compile | 一次 Compilation 执行完成 | | invalid | 当遇到文件不存在、文件编译错误等异常时会触发该事件,该事件不会导致 webpack 退出 |

输出

将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中