Skip to content

🔰 Bun 1.0 发布了,以后 Node.js 项目谁还用 Webpack 与 pnpm?!是时候祭出大杀器 Bun了(一)

🕒 Published at:

img

Bun 1.0 发布了,以后 Node.js 项目谁还用 Webpack 与 pnpm?!是时候祭出大杀器 Bun了(一)

bun 绝对值得投入时间学习一下,对程序员来说,它像 Vite 一样,可以十倍百倍提升开发体验和开发效率。

Node.js 在 2009 的发布可谓石破天惊,天才程序员 Ryan Dahl 基于谷歌浏览器的 V8 引擎,一举将 JavaScript 这个客户端语言带到了服务器端的广阔天地。

JavaScrpt 的异步回调机制、简单的语法、超低的门槛、解释执行方便热部署等特征,迅速使其占领了服务器端的业务接口编写领域,这个领域向数据库要数据,向业务底层要执行结果,向浏览器客户端以 RESTFul 接口的形态提供数据,简单、直观,该领域使用 JavaScript 编写再合适不过了。

Node.js 的出现,让 JavaScript 的能力范围从前端一下拓展到了后端,加上后来 2013 年在 Node.js 的启发下发布的桌面开发框架 Electron,又拓展到了桌面端,JS 成为了大前端语言、全栈语言。(一般而言我们说全栈,狭义上指前端、后端、数据库、服务器等,广义上讲还包括 APP、桌面软件开发。在 App 开发上,有比较知名的 React Native、ionic、uniapp 等,在桌面开发领域,选择即 Electron。)

Node.js 包管理工具的演进

Node.js 发展起来以后,在它上面产生了一系列的业务开发框架和类库,大多数都是为了提交开发效率和工程协作体验的。下面拣一些常见的内容说一下:

1,例如工程化与打包框架 webpack,及随着 webpack 一起诞生的是大名鼎鼎的工程文件 package.json。

2,为了解决 JS 的弱类型问题,发明了 TypeScript,并由此诞生了.ts 文件及编译 ts 文件的 tsc、babel 编译器。

3,为了倒转控制,大牛程序员发明了响应式框架 React 与 Vue。以前在 jQuery 开发时代,程序员需要主动找到页面上的 HTML 节点,然后更新节点的值;响应式框架不是,程序员只需要指定节点绑定的数据,在改变数据后,框架负责将更改后的数据同步到节点上。响应式框架相当于是在页面中运行的一个小的 JS 运行时,时刻帮助程序员监视着页面上的每一个变化。

4,为了在工程化的 Node.js 项目中方便加载字体、图片、css、svg 等内容,大牛程序员们又编写了各种加载器,例如 file-loader、css-loader、sass-loader、less-loader、style-loader、url-loader、font-loader、svg-loader 等,不要纠结它们的名字,只需要知道这些加载器都是针对某一个文件类型的预处理程序就可以了。为什么要编写它们?因为工程化的 Node.js 项目要进行编译和捆绑,在此之前,需要掌控项目中的一切资源。这些加载器在配置文件中都有特定配置格式,要正解编写它们,基本每次都需要查文档或谷歌。

5,与 Node.js 同时发布的,还有一个 CommonJS 模块化规范。模块化让类库的独立导出和复用变成了可能,一个个类库像一个独立的有特定功能的积木一样,开发者可以自由地在自己的项目引入和使用。为了方便管理这些类库,大牛程序员们又编写了 npm 这样的包管理工具,关于包的下载、安装、更新、移除等操作,使用指令就可以了。这些包作为依赖项在工程文件 package.json 中还被记录了下来,使用 npm i 还可以一键安装,这个时期的程序员太幸福了。

6,幸福的好景不长,由于包管理的自动化,很快一个 Node.js 项目的依赖项就失去了控制。当我们安装一个包时,不只是会安装它本身,它依赖的包也会自动安装,所以项目的 node_modules 目录(包的本地安装目录)经常有很多子目录,一个 Node.js 项目的总体积达到几百甚至上千 MB 都成为常态。依赖项很多,体积变大,不仅下载、安装速度很慢,有时候还可能发生依赖冲突。我们举个例子,我们的项目依赖了 A 和 B 两个包,这两个包又依赖了 C,但却是 C 的不同版本,且 C 的这两个版本还不同,甚至有冲突,这就带来了隐藏的工程化灾难。JS 本身是在页面上的单线程环境中运行中,各个包使用的内存空间是同一个空间,相互之间没有隔离,发生奇奇怪怪的依赖项异常一点也不稀奇。如果你没有遇到过,只能说你还没有走到工程化的前沿,在边缘地带什么地雷都可能踩到。

7,为了解决包冲突的问题,大牛程序员发明了 yarn。一般情况下,团队规范能被允许使用 yarn,就不会使用 npm。有人可能会问,既然 yarn 在包管理策略上优于 npm,为什么团队规范会禁止使用?可能因为领导的脑子有坑,制定了某条僵硬的教条,他自己都不明白为什么,这样的人在专制的体制下并不鲜见。yarn 并不是没有缺点,从上面的对比截图也可以看出来,它的下载速度变慢了。

8,下载、安装速度慢,是 Node.js 项目长期以来,自诞生以后,一直存在,一直被开发者诟病的缺点。为了解决这个问题,大牛程序员回归初心,开发了 pnpm,在 npm 前面加了一个 p,使用并发的方式下载类库并直接在终端里给出实时的数字反馈。这个改进让开发者的下载体验感觉舒服多了。于是,在团队规范允许的情况下,能使用 pnpm,就不使用 yarn 和 npm。

image-20230923115301691

9,但是,pnpm 的下载速度还是慢,它只是在一定程度上改善了原本就很慢的下载速度,这一点从上面的下载速度对比上可以看出来。bun 在 npm、yarn、pnpm 成功经验的基础之上,总结前人智慧,采用全局缓存+并发下载的策略,一举将下载速度提升了一个数量级。

主流包管理工具下载比拼

为了验证官方的说辞,我准备亲自试用一下。我选了我的博客项目,使用下面的指令依次清扫上次安装留下的痕迹:

bash
rm -rf node_modules pnpm-lock.yaml
rm -rf node_modules yarn.lock
rm -rf node_modules package-lock.json
rm -rf node_modules bun.lockb(这一步其实不需要)
rm -rf node_modules pnpm-lock.yaml
rm -rf node_modules yarn.lock
rm -rf node_modules package-lock.json
rm -rf node_modules bun.lockb(这一步其实不需要)

每个包管理工具的lock文件都不一样,这也是为了不冲突。依次执行下列指令,使用三个包管理工具分别进行下载安装:

bash
echo `date` && pnpm i && echo `date`
echo `date` && yarn && echo `date`
echo `date` && npm i && echo `date`
echo `date` && bun i && echo `date`
echo `date` && pnpm i && echo `date`
echo `date` && yarn && echo `date`
echo `date` && npm i && echo `date`
echo `date` && bun i && echo `date`

为了测试公平起见,我事先关掉了梯子(但保留使用了国内仓库源)。echo 指令是为了查看执行安装指令前后的时间点,其实没有这两个 echo 指令也可以,因为无论是哪个安装工具,在安装完成后都会主动向我们报告耗时时间。

结果发现:

1,pnpm 耗时 8.5s

pnpm 的下载体验基本还是令人满意的。

2,yarn 耗时 27.92s

在这一步时,在关掉梯子的情况下,出现了“info There appears to be trouble with your network connection. Retrying...”异常,这可能是由于网络不通引起的。打开梯子,再次执行 yarn 会快很多,也可以顺利完成安装指令。

3,npm 耗时 ∞

在执行这一步时,在关掉梯子的情况下,一直卡在某个节点;在打开梯子以后,仍然卡在了某个地点,无法继续了。

4,bun 耗时 518ms

bun 的表现确实一骑绝尘,与官方宣称的比较匹配。

包管理工具耗时
bun0.518s
pnpm8.5s
yarn27.92s
npm

在我的测试中,我只是删除了工程项目下的 node_modules 文件夹及相关的 lock 文件,并没有删除公共的、共享的包管理工具缓存目录。如果严格执行,bun 的表现应该没有这么优秀。500ms 的速度已经比 rm -rf 指令的执行时间还要短,bun 无论是在网络下载还是在文件移动上确实做了足够的优化。

bun 作为一个包管理工具,它的下载速度是让人满意的。但它不仅仅是一个包管理工具,事实上它作为一个网络基础软件,它还替代了 Node.js,它是在网络基础软件这个层次上,集合了众多成功工具的优点并替掉了它们。Vite 是在业务软件开发这个层面集合与替换的,bun 是在服务器网络基础软件这个层次汇总与替换的。(更多的内容下一篇再说。)

如何安装 bun?

最后说一下它的安装方法,在 Mac 或 Linux 上直接在终端里执行下列指令:

bash
curl -fsSL https://bun.sh/install | bash
curl -fsSL https://bun.sh/install | bash

该指令先将安装器下载到本地,紧跟着进行安装。

如果是 Windows 系统,目前 bun 仅提供了限于运行时功能的版本,并且还需要先安装 WSL(一种 Windows 下面的子虚拟机环境)。为什么会这样?因为程序员现在使用 macOS 开发软件是共识,而在服务器端,也极少选择和使用 Windows Server 系统。微软最成功的服务器端操作系统是 Windows 2000,现在它已经被 CentOS、Ubuntu 等 Linux 发行版本替换了。

所以,全栈开发人员,找一个 macOS 笔记本作为开发本,然后开始试用 bun 吧,它将大幅提升你的开发体验和产品运行效率。(下一篇继续介绍它的更多功能,关于内置的热加载、环境变量读取等功能。)

参考