乐趣区

关于javascript:用-Vite-加速你的生产力

目前组里的业务组件库因为一些历史背景起因,源码和展现站点分为两个独立的我的项目工程保护,而市面上对于组件、组件库、工具库的源码和站点在一个仓库保护或者采纳 MonoRepo 的形式开发和保护,因而在不扭转我的项目架构的前提下(临时不要纠结为什么不放在一起保护),咱们对于效率协同和工程化方面进行了一系列的演进,上面首先介绍下咱们以后面临的问题:

面临的问题

npm link

因为源码和站点保护在两个工程下,在本地开发的时候如何关联两个我的项目是首先面临的问题,最后咱们采纳了 npm link 的形式,然而因为组件库和站点均是基于 react hook 开发,因而每次进行组件迭代开发都须要经验上面几步:

  • 站点下: cd node_modules/react && npm link 和 cd node_modules/react-dom && npm link
  • 源码下: npm link react && npm link react-dom
  • 源码下: npm link
  • 站点下: npm link 源码

不难发现,这样的计划有以下痛点(每个新参加开发的同学都会吐槽 diss):

  • 操作繁琐易出错;
  • yarn 和 npm 混和应用使得 link 问题频出;
  • link 断链;

站点 & 源码,双编译

这一版咱们齐全摈弃了 npm link,采取了比拟 hack 的形式:

  • 源码 watch 文件变更,实时编译构建 ESM;
  • 源码 watch ESM 变更,实时同步到站点 node_modules 下;
  • 站点 watch node_modules 下组件 ESM 变更,热更新;

不难发现,这样的计划有以下痛点:

  • 监听 node_modules 变更,姿态很 hack;
  • 双边 watch + 编译,重大耗费内存资源;
  • 热更新工夫 = 组件 ESM 编译工夫 + 同步推送工夫(能够忽略不计)+ 站点编译工夫,10s+ 妥妥的;

站点单编译

既然站点和源码都具备编译构建能力,为什么不缩小一次编译构建呢?为此咱们进行了第三次优化降级:

  • 源码 watch 文件变更,实时同步源码到站点缓存目录下;
  • 开发环境下,站点 import node_modules 下 ESM 变更为 import 缓存目录下组件源码;
  • 站点 watch 缓存目录下组件源码变更,热更新;
    尽管这次降级后曾经解决了大部分的问题,然而还是存在问题。

源码本地开发的优化使得站点编译压力的减少:

  • 热更新慢:改个文案 hotreload 2s +;
  • 冷启动更慢:60s 妥妥的;

其实到当初这一步问题曾经肯定水平往 webpack 衍生计划的通病上靠了,因而,咱们把指标聚焦在了新的构建工具上。

为什么抉择 Vite?

上面我列举了一常见的构建工具以及以及一些选型思考。

首先是 Webpack 以及 Webpack 衍生计划:

  • 基于 CRA 封装的业务脚手架;
  • CRA;
  • Webpack 轻量级配置;

基于 Webpack 的计划和目前应用的脚手架差别不大,收益不显著,并且从根本上也解决不了 Webpack 带来的生产力问题。

接下来是目前比拟火的基于 ESM 的古代计划:

  • Snowpack
  • Vite

对于比拟尤大的文章更有说服力:比照。

此外,就我集体而言,我感觉尤大在华人社区以及国内的影响力更大一些,因而尤大开源的工具在国内社区活跃度会更高一些,关注度也会更高,对于后续的可继续倒退也比拟无利,因而在选型上咱们抉择了 Vite。

成绩收益

  • 秒级冷启动:60s+ => 3s-(缓存失效后 300ms 左右)
  • 毫秒级热更新:2s+ => 1s-(sync + hotreload)

喜大普奔,收效显著!!!

Vite 为什么快?

首次冷启动:esbuild 预编译,生成缓存



再次冷启动:利用缓存

冷启动

首先冷启动为什么快,因为 Vite 基于原生 ESM,也就是说 Vite 将原来 Webpack 前置构建 bundle 的工作交给了性能强悍的当初浏览器来做,所以冷启动工夫大幅缩减(毕竟冷启动最耗时的就是剖析代码构建 bundle)。

而在 Vite 中,正如官网文档介绍的那样,Vite 将咱们的代码气氛了依赖和源码两局部:

  • 依赖:大多为在开发时不会变动的纯 JavaScript。Vite 将会应用 esbuild 预构建依赖。esbuild 应用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍
  • 源码:通常蕴含一些并非间接是 JavaScript 的文件,须要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都须要同时被加载(例如基于路由拆分的代码模块)

以 Webpack 为代表的“bundle based dev server”,在冷启动前须要依赖诸如 babel 之类的工具对代码进行剖析并编译生成可运行的 bundle,这一 构建时 的过程造成了冷启动工夫过长。

而对于“ESM base dev server”来说,dev server 依赖的是咱们 ESM,而咱们的代码自身就是以 ESM 编写的,因而进去要告知 dev server 指标模块门路加载即可,编译解析交给浏览器的 运行时 去解决,从而大大减速了咱们的冷启动。

热更新

基于原生 ESM

在 Vite 中,HMR 是在原生 ESM 上执行的。和冷启动一样的情理,当咱们批改了一个文件后,不须要在从新编译了,热更新也就大大减少耗时了。

配合 http 头

Vite 充份利用了 http 缓存,这也是咱们在本地开发时候看到的一个和 webpack 比拟大的不同,network 中充斥了大量模块申请。

  • 源码局部:304 配合 ETag 协商缓存

  • 依赖模块:强缓存

Webpack to Vite?

那么如何安稳的从 Webpack 迁徙到 Vite?其实,当你依照 Vite 文档落地的时候曾经兼容 80% 的 Webpack 场景。只须要思考一些额定 case:

ESM 及 ESM 衍生问题

Vite 利用了 esBuild 去预构建 ESM,因而对包的要求绝对严格,对于 esBuild 预编译失败的场景须要 case by case 解决。

例如:

esBuild 预编译失败

这里以 react-virtualized 为例,react-virtualized 的 WindowScroll.js 下引入了 flow 的类型文件导致预编译失败。

能够写 esBuild 插件、写 resolutions、拉包本地改。

dep-scan 依赖剖析失败

以 react-infinite-scroller 为例,他在 package.json 中 ESM 读取目录指向了发包后被疏忽的 src 源码目录,导致 dep-scan 插件查找模块失败。

ESNext bundle

Vite 构建过程由 esBuild 接管,而 esBuild 反对的 target 的最低版本为 es6,因而想要构建兼容性更强的 bundle 须要对 Vite 的产出二次编译或者应用官网给出的基于 SystemJS 的计划。

上面这张图是截取的 Vite 官网的兼容性一节:

应用官网插件:

  • babel 转译并注册为 System.js 模块;
  • 增加 System.js 运行时;

说在最初

向咱们组件库的展现站点或者外部零碎的工程项目说用了就用了,然而理论投入到对外的我的项目时咱们也不得不思考一些问题:

老本

单说从 Webpack 切换到 Vite 老本很低,甚至比 Webpack 的大版本升级还要简略。然而从 Webpack 到 Vite 不仅仅是构建工具的转换而是整个生态的迁徙,那么对于历史我的项目已存在的 babel 插件、Webpack 插件等都须要等量替换,这是一个老本。此外,就像上一节说的那些,对于一些不标准的三方包咱们也须要做额定的适配,这也是一个老本。

收益

从目前看,Vite 带来的工程效率收益比拟高,然而就我集体而言尝试的仅是简略的展现站点,并不能严格和理论的业务工程划等号,并且企业级我的项目工程量和复杂度都比拟大,Vite 是否能合乎预期的带来收益我集体还不敢保障。

危险

最初,因为波及到了 ESM,就算官网给出了 SystemJs 版本的兼容插件,然而理论投入对外我的项目的兼容性危险也还是未知的。

退出移动版