Appearance
Babel
Babel 主要的作用就是语法转换,Babel 的整个过程分为三个部分:
- 解析,将代码转换为抽象语法树(AST);
- 转换,遍历 AST 中的节点进行语法转换操作;
- 生成,根据最新的 AST 生成目标代码。
其中在转换的过程中就是依据 Babel 配置的各个插件去完成的。插件示例:
js
const createPlugin = (name) => {
return {
name,
visitor: {
FunctionDeclaration(path, state) {},
ReturnStatement(path, state) {},
}
};
};可以看到 Babel 的插件也是返回一个函数,和 umi 的很相似。但是 Babel 插件的运行却并不是基于发布订阅的事件驱动模式,而是采用访问者模式。Babel 会通过一个访问者 visitor 统一遍历节点,提供方法及维护节点关系,插件只需要在 visitor 中注册自己关心的节点类型,当 visitor 遍历到相关节点时就会调用插件在 visitor 上注册的方法并执行。
Vite
Vite 是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:
- 一个开发服务器:基于原生 ES 模块的开发服务器,能够快速启动开发服务,并且实现速度快到惊人的模块热更新(HMR)
- 一套构建指令:基于 Rollup 打包源码,并且是预配置的,,可输出用于生产环境的高度优化过的静态资源
Vite 意在提供开箱即用的配置,同时它的 插件 API 和 JavaScript API 带来了高度的可扩展性,并有完整的类型支持。
基本原理
首先 Vite 分为开发模式和生产模式:
开发模式:
Vite 提供了一个开发服务器,基于原生的 ESM,当代码中出现 import 的时候,发送一个资源请求,Vite 服务器拦截请求,根据不同文件类型,在服务端完成模块的改写(比如单文件的解析编译等)和请求处理,实现真正的按需编译,然后返回给浏览器。请求的资源在服务器端按需编译返回,完全跳过了打包这个概念,不需要生成一个大的 bundle。服务器随起随用,所以开发环境下的初次启动是非常快的。而且热更新的速度不会随着模块增多而变慢,因为代码改动后,并不会有 bundle 的过程。
Vite 拦截请求之后会做以下事情:
- 处理 ESM 语法,比如将业务代码中的
import第三方依赖路径转为浏览器可识别的依赖路径 - 对
.ts、.vue等文件进行即时编译 - 对 Sass/Less 的需要预编译的模块进行编译
- 和浏览器端建立 socket 连接,实现 HMR
生产模式:
利用 Rollup 来构建源代码。
Rollup
Rollup 也是模块打包工具,与 Webpack 相比 Rollup 更适合打包纯 js 的类库。同样 Rollup 也具有插件机制。一个典型的 Rollup 插件:
js
export default function myExample() {
return {
name: 'my-example',
resolveId(source) {},
load(id) {},
};
}Rollup 插件维护了一套同步/异步、串行/并行、熔断/传参的事件回调机制,不过这部分并没有单独抽出类库,而是在 Rollup 项目中维护的。通过插件控制器(src/utils/PluginDriver.ts)、插件上下文(src/utils/PluginContext.ts)、插件缓存(src/utils/PluginCache.ts),完成了提供插件 api 和插件内核的能力。
Webpack
Webpack 整体基于两大支柱功能:一个是 loader,用于对模块的源码进行转换,基于管道模式;另一个就是 plugin,用于解决 loader 无法解决的问题,顾名思义,plugin 就是基于插件机制的。来看一个典型的 Webpack 插件:
js
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('webpack 构建正在启动!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;Webpack 在初始化时会统一执行插件的 apply 方法。插件通过注册 Compiler 和 compilation 的钩子函数,在整个编译生命周期都可以访问 compiler 对象,完成插件功能。同时整个事件驱动的功能都是基于 Webpack 的核心工具 Tapable。
构建提速体系化思路
- 延迟处理
- 缓存
- Native Code (swc, esbuild, ..)
