Esbuild在Vite里面都干了些什么事

640 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情

  • Hello,这里是mouche,当然你也可以叫我某车,反正大家都爱这么叫😁

一、依赖预购建

  • 我们应该都知道Vite基于浏览器的ESM的支持实现了no-bundle的服务
  • 这个no-bundle的服务也仅限于开发过程中针对项目源代码,对于第三方依赖而言,Vite还是选择了对其进行打包(bundle)
  • Esbuild提供了打包API:esbuild -build- API
  • 根据指定的单个或者多个入口,分析依赖,并使用 loader 将不同格式的内容转化为 js 内容,生成一个或多个 bundle 文件

原因

  • 第三方依赖不是全部都支持ESM(毕竟是后面才出现的), 但是CommonJSUMD相关代码无法在Vite直接运行,因为Vite的开发服务器将所有代码默认为原生 ESM,那么就需要有东西来将它做一个转换
  • 每有一个import就会发起一个HTTP请求,在依赖层级比较深,依赖模块比较多的时候,无疑会触发大量HTTP请求产生,而我们的浏览器比如说Chrome对于同域名的请求,一次只允许并发6个,所以处理大量的请求无疑会慢慢慢。。。,那么就需要有个东西来对他进行一个打包

操作

主要就是针对上述的原因进行操作

  • 将其他格式(如 UMDCommonJS)的产物转换为ESM格式,使其在浏览器能够基于 <script type="module"><script>的方式正常加载代码
  • 打包第三方依赖的代码,将各个第三方依赖代码分散的文件合并到一起减少 HTTP 请求数量,避免页面加载性能劣化

Vite 1.x使用Rollup来做这件事,但是Vite2.x采用ESbuild来完成第三方依赖的预构建,原因呢,就是它真的 image.png

作为打包工具的缺陷

  • 不支持降级到ES5的代码,这就是说在低端的浏览器代码可能会跑不起来
  • 不支持const enum 的语法,如果使用这些语法则会报错
  • 核心代码是用golang编写,用户使用的直接是编译出来的binary代码和一堆js的胶水代码,binary代码几乎没法断点调试
  • 不支持自定义代码分割(Code Splitting)策略,降低了拆包优化的灵活性
  • 相比于webpackrollup庞大的plugin插件支持, ESbuild目前还是比较少的
image.png

所以目前vite还是采用在生产环境还是采用Rollup, 不过官网也表示了当未来这些功能稳定后,也不排除使用 esbuild 作为生产构建器的可能 image.png

二、作为转译工具

  • Esbuild提供转译API:esbuild -transform API
  • 通过这个 api,我们可以将 tsjsxtsx 等格式的内容转化为 js。 transfrom 只负责文件内容转换,并不会生成一个新的文件

支持ts

  • Vite 天然支持引入 .ts 文件
  • TS(X)/JS(X)单文件的编译上,Vite使用Esbuild进行了语法转译
  • 原因也是因为它Vite使用EsbuildTypeScript转译到JavaScript的速度,约是tsc速度的20-30倍,同时HMR更新反映到浏览器的时间小于50ms
  • ESbuild转译的能力是通过Vite插件插件实现的,这个插件在开发和生成环境都会执行,所以它也用于生产环境中

局限

  • Vite 仅执行文件的转译工作,并 不执行 任何类型检查。并假设类型检查已经被你的 IDE 或构建过程接管了
  • 所以使用Vite搭建vue项目的话,在打包的时候,一般会先给他做一下类型检查 image.png

三、压缩

  • 在生产环境中 Esbuild 压缩器通过插件的形式融入到了 Rollup 的打包流程中
  • 我们在前面提过,Esbuild是基于Golang编写的, 传统的方式Terser是使用JS开发的; 对于压缩这种CPU密集型的工作,性能比不上Golang这种原生语言
  • 同时,ESbuild是共享AST的,而TerserAST操作的时候,在各个工具中是无法共享的
  • 所以使用它的原因也可以是 “快”