对于 webpack 的认识始终停留在对脚手架的使用, 不得不说脚手架既方便又好用, 修改起来也方便, 只需要知道 webpack 中各个配置项的功能, 于是对于我们来说, webpack 始终就是一个黑盒子, 我们完全不清楚里面是如何去运作的. 打包时报错, 就只能借助 google 来协助帮忙解决问题, 至于为什么要这样解决, 什么原理, 不管, 能解决就好. 那么, 了解一下基本原理也是有必要.
概念
言归正传, 我们一起了解一下 webpack 运行基本原理, 首先先明白几个核心概念,
Entry: 入口, webpack 构建的起始
Module: 模块, webpack 里面一切皆模块, 也是代表着文件, 从 Entry 配置的入口文件开始, 递归找出依赖的模块
Chunk: 代码块, 找出递归依赖模块经转换后组合成代码块
Loader: 模块转换器, 也就是将模块的内容按照需求装换成新内容
Plugin: 扩展插件, webpack 构建过程中, 会在特定的时机广播对应的事件, 而插件可以监听这些事件的发生
流程
webpack 构建流程, 详细过程如下:
初始化: 从配置文件或是 shell 读取与合并参数, 得到最终参数, 实例化插件 new Plugin()
开始编译: 通过上一步初始化得到的最终参数, 初始化一个 Compiler 对象, 加载插件 (依次调用插件中的 apply 方法), 通过执行 Compiler.run 开始编译
确定入口: 根据配置中 entry 找出所有入口文件
编译模块: 从 entry 出发, 调用配置的 loader, 对模块进行转换, 同时找出模块依赖的模块 (如何找? 见下文), 依次递归, 直到所有依赖模块完成本步骤处理
完成模块编译: 这一步已经使用 loader 对所有模块进行了转换, 得到了转换后的新内容以及依赖关系
输出资源: 根据入口与模块之间的依赖关系, 组装成一个个 chunk 代码块, 并且生成文件输出列表
输出成功: 根据配置中的输出路径和文件名, 将文件写入文件系统, 完成构建
事件
整个构建流程会发生很多的事件, 来供 Plugin 监听, 这些事件具体的可以分为三个阶段, 分别是初始化阶段, 编译阶段, 输出阶段, 那么具体有哪些事件, 这里按阶段分别介绍,
初始化阶段
事件 | 作用 |
---|---|
初始化 | 从配置文件或是 shell 读取与合并参数,得到最终参数,依次实例化插件 new Plugin() |
实例化 Compiler | 通过上一步初始化得到的最终参数,初始化一个 Compiler 对象,负责监听文件和启动编译,全局只有一个 Compiler 对象 |
加载插件 | 依次调用插件中的 apply 方法,同时也会将 Compiler 实例传入,就可以调用 Webpack 提供的 api,Compiler 实例可以说是就是 Webpack 的实例 |
environment | 将 node.js 风格的文件系统应用到 compiler 对象,便可以直接通过 compiler 来对文件进行操作 |
entry-option | 读取配置中的 entry,依次实例化出对应 EntryPlugin,为后面该 entry 的递归解析工作做准备 |
after-plugins | 调完所有内置和配置的插件的 apply 方法 |
after-resolvers | 根据配置初始化 resolvers,resolvers 负责在文件系统中寻找制定路径的文件 |
编译阶段
事件 | 作用 |
---|---|
run | 启动一次新的编译,调用 Compiler.run() |
watch-run | 和 run 类似,区别在于它是在监听模式下进行编译的,这个事件可以获取哪些文件发生了变化从而导致新的一次编译 |
compile | 告诉插件新的一次编译即将启动,并且给插件带上 compiler 对象 |
compilation | 每当检测到文件的变化,都会有一次新的 compilation 被创建,一个 compilation 对象包含了当前的模块资源、编译生成的资源、变化的文件等等的属性和方法,同时记住,在很多事件的的回调中都会将 compilation 传入,以便使用 |
make | 一个新的 Compilation 创建完毕,那么就会从 entry 配置中开始读取文件,使用配置好的 loader 对文件进行编译,编译完后再找出文件依赖的文件,递归地去编译和解析 |
after-compile | 一次 Compilation 执行完成 |
invalid | 文件编译错误等异常触发该事件, 不会导致 webpack 退出 |
Compilation 的事件
事件 | 作用 |
---|---|
build-moudle | 使用对应的 loader 去转换一个模块 |
normal-module-loader | 在用 loader 转换一个模块后,会使用 acorn 解析转换后的内容输出对应的抽象语法树(ast), 以便 webpack 后面分析代码使用 |
program | 从配置的入口开始,分析生成的 ast,遇到 require 等导入语句时,便会将其加入依赖模块列表,并且对找出的依赖进行递归分析,最终可以弄清所有依赖关系 |
seal | 所有模块及其依赖的模块都通过 Loader 转换完成,根据依赖关系生成 chunk |
输出阶段
事件 | 作用 |
---|---|
should-emit | 所有需要输出的文件都生成,准备输出,询问哪些文件需要输出,哪些不需要输出 |
emit | 确定好要输出哪些文件后,并执行文件输出,可以在这里获取和修改输出的内容 |
after-emit | 文件输出完毕 |
done | 完成一次完整的编译和输出流程 |
failed | 编译和输出过程中运到异常,导致 webpack 退出,会直接到这个步骤,可以在这里获取具体原因 |
总结
Webpack 是很好的前端资源加载和打包工具, 在 webpack 里一切皆模块, 很好地处理文件之间的依赖关系, 这里我们介绍的是些理论性的知识, 了解基本概念, 知道整个流程是怎么样的, webpack 是串行流水线运行的, 工作期间会有很多广播事件, 来供插件使用, 这里我们介绍了各个阶段的事件以及作用, 具体代码表示形式, 后续文章会引入.
来源: https://www.cnblogs.com/wuxiaobin/p/10390381.html