告别Node.js:2025年,我为何全面拥抱Bun

大家好,我是农村程序员,独立开发者,行业观察员,前端之虎陈随易。

  • 关注公众号:陈随易,获取最新观察和思考。
  • 个人网站 1️⃣:chensuiyi.me
  • 个人网站 2️⃣:me.yicode.tech

如果本文能给你提供启发或帮助,欢迎动动小手指,一键三连 (点赞评论转发),给我一些支持和鼓励,谢谢。


Node.js 诞生于2009年,由 Ryan Dahl 创建,是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。

它实现了一个革命性的理念:将JavaScript从浏览器中解放出来,使其能够在服务器端运行

如今15年过去了,Node.js 彻底改变了 Web 开发格局,让 JavaScript 成为真正的全栈语言。它被广泛应用于 Web 服务器、API 开发、实时通信应用、命令行工具和桌面应用程序开发。

尽管如此,Ryan Dahl 还是在2012年离开了它,并转而投入到新的 JS 后端运行时 Deno 的研发中。

2018年,Ryan Dahl 在柏林 JS 大会上演讲,主要讲述了过去他在设计 Node 时犯的一些错误,包括 Node 安全、构建系统 (GYP)、package.json 等方面上的问题,并阐述了开发新项目 Deno 背后的一些故事、原因和未来规划。

那么让我们再次回顾一下 Ryan Dahl 眼中 Node.js七宗罪

遗憾:未能信守约定

2009年制定了异步抽象机制的约定,2010年却将其清除。若坚持统一约定,可能会加速标准化与异步/等待机制的推进。如今 Node 中的许多异步 API 已严重过时。

遗憾:安全性

V8 本身是优秀的安全沙箱,但 Node 未能充分利用这一特性来实现应用级别的安全控制。比如,代码检查工具不应该拥有对整个计算机和网络的完全访问权限。

遗憾:构建系统 (GYP)

选择 GYP 作为构建系统是个错误。Chrome 后来放弃 GYP 转向 GN,导致 Node 成为唯一使用 GYP 的项目。更应该为用户提供核心外函数接口 (FFI),而非引导用户编写 C++绑定。

遗憾:package.json

默许了 package.json 成为标准,导致了中心化的模块管理方式。这引入了 "模块即目录" 的抽象概念,实际上并非必要。package.json 如今包含大量非必要信息,而直接使用文件路径和 URL 就能定义版本,无需列出依赖。

遗憾:node_modules

极大增加了模块解析算法的复杂性。虽然 "默认本地依赖" 理念不错,但严重偏离了浏览器语义,如今已难以修正。

遗憾:require ("module") 没有加上扩展名 "。js"

这种设计与浏览器 JavaScript 工作方式不符。在 HTML 中使用 script 标签时无法省略 "。js" 扩展名。模块加载器必须尝试多个位置查询文件系统以猜测用户意图,增加了不必要的复杂性。

遗憾:index.js

仅因为有 index.html 就使用 index.js 的命名方式,给模块加载系统带来了不必要的复杂性。在支持 package.json 后,index.js 已失去存在意义。

以上就是 Ryan Dahl 对 Node.js 设计中的遗憾,那么后来者 DenoBun 解决了这些问题了吗?同样很遗憾地告诉你,无法解决,只能妥协,只能打补丁。

因为 Node.js 已经占据了先驱者的生态位,是它制定了规则,创造了一切,已经根深蒂固,盘根复杂。

如果你要吃掉 Node.js 的蛋糕,那你必须成为 Node.js 的超集,就像 TypeScript 之于 JavaScript 一样。

所以我们看到,尽管千不般,万不愿,还是在 Deno v2 版本,向全世界发布:我们对Node.js的兼容又达到了一个新的高度

那么我为什么更看好 Bun 呢?

我把 Bun 的功能特意翻译成中文,读者朋友们可以点击大图对比一下,同时呢,分享以下部分在 Bun 中我觉得非常有意思的功能。

Workspaces

json 复制代码
{
    "name": "my-project",
    "version": "1.0.0",
    "workspaces": ["packages/*"],
    "devDependencies": {
        "example-package-in-monorepo": "workspace:*"
    }
}

Bun 默认支持 workspaces 功能,不需要 npm,也不需要 pnpm,非常方便。

Patch 依赖

Bun 允许直接修改第三方包代码,无需 fork 仓库。遇到依赖 bug 时,可创建补丁并在每次安装时自动应用,让修复不依赖上游更新。

而在 Node.js 中,这个功能由专门的 patch-package 包处理。

单文件可执行文件

bash 复制代码
bun build ./cli.ts --compile --outfile mycli

$ ./mycli
Hello world!

通过以上命令,就能生成一个 .exe 可执行单文件,一个 Web 服务也能打包,丢给使用者,点击就能启动 Web 服务。

js 复制代码
import myEmbeddedDb from './my.db' with { type: 'sqlite', embed: 'true' };

console.log(myEmbeddedDb.query('select * from users LIMIT 1').get());

不仅如此,sqlite 也给你内置了,也就是说,这个 .exe 文件居然自带了内嵌的数据库功能。

js 复制代码
// 内嵌文件
import icon from './icon.png' with { type: 'file' };
import { file } from 'bun';

export default {
    fetch(req) {
        // Embedded files can be streamed from Response objects
        return new Response(file(icon));
    }
};
js 复制代码
// 内嵌目录
import icon from './public/assets/icon.png' with { type: 'file' };
import { file } from 'bun';

export default {
    fetch(req) {
        // Embedded files can be streamed from Response objects
        return new Response(file(icon));
    }
};

还有呢,也能内嵌文件和目录,也就是说,你可以完全把一个 后端接口项目+一个后台管理 打包成一个 .exe 文件,丢给使用者,真是极其方便。

不过,Deno 显然不愿意屈居人后,也在 v2 版本支持了这个内嵌功能,目前落后的只有 Node.js 了,官方默认的 SEA 方案还差很多。

自动安装依赖

js 复制代码
import { foo } from 'foo'; // 安装最新版本

foo();

以上代码,如果你项目中没有 node_modules 目录,那么你第一次通过 Bun 执行脚本的时候,node_modules 目录会自动创建,foo 也会自动安装。

这种自动挡的能力,Java 应该是佼佼者。

HTML 和静态站点

Bun 还可以直接托管 html 文件,并立即启动一个 web 服务器,并设置对应路由。

也就是说,Bun 在一定的程度上,可以替代 Nginx,而且细节方面的支持更好。

SQL

js 复制代码
import { sql } from 'bun';

const users = await sql`
  SELECT * FROM users
  WHERE active = ${true}
  LIMIT ${10}
`;

// Select with multiple conditions
const activeUsers = await sql`
  SELECT *
  FROM users
  WHERE active = ${true}
  AND age >= ${18}
`;

Bun 自带了 SQL 功能,简单的 SQL 操作不用再额外安装第三方依赖了。

不过目前仅支持 PostgreSQLMysql 将在后续支持。

静态存储协议

js 复制代码
import { s3, write, S3Client } from 'bun';

// Bun.s3 reads environment variables for credentials
// file() returns a lazy reference to a file on S3
const metadata = s3.file('123.json');

// Download from S3 as JSON
const data = await metadata.json();

// Upload to S3
await write(metadata, JSON.stringify({ name: 'John', age: 30 }));

// Presign a URL (synchronous - no network request needed)
const url = metadata.presign({
    acl: 'public-read',
    expiresIn: 60 * 60 * 24 // 1 day
});

// Delete the file
await metadata.delete();

Bun 内置了对 s3 协议的支持,这是静态存储的通用协议,这个功能,让我们操作静态存储就行操作本地文件一样简单方便。

虽然这个功能在前段时间刚出来时遭到了很多人的反对,但是真的集成为内置功能的时候,发现还是挺香的。

活跃且积极的创始人

最后呢,Bun 的创始人非常活跃,非常积极,从其 2.3 万条帖子就不难看出来。

如果把 Deno 比作一个绅士,那么 Bun 就是名副其实的精神小伙。

正所谓,乱拳打死老师傅,如此活跃的创始人,更新如此积极的 Bun,如何让人不看好呢。

所以,我准备在2025年,告别 Node.js,全面拥抱 Bun 生态。

关注公众号,分享更多技术观察和思考。

相关推荐
Pandaconda1 分钟前
【后端开发面试题】每日 3 题(十二)
数据库·后端·面试·负载均衡·高并发·后端开发·acid
谭知曦12 分钟前
Scheme语言的压力测试
开发语言·后端·golang
uhakadotcom16 分钟前
实时计算Flink版:解锁数据处理新世界
后端·面试·github
Dontla16 分钟前
黑马node.js教程(nodejs教程)——AJAX-Day01-04.案例_地区查询——查询某个省某个城市所有地区(代码示例)
前端·ajax·node.js
uhakadotcom17 分钟前
Hologres实时数仓引擎:简化数据处理与分析
后端·面试·github
威哥爱编程18 分钟前
vue2和vue3的响应式原理有何不同?
前端·vue.js
呆呆的猫21 分钟前
【前端】Vue3 + AntdVue + Ts + Vite4 + pnpm + Pinia 实战
前端
qq_4560016523 分钟前
30、Vuex 为啥可以进行缓存处理
前端
带娃的IT创业者31 分钟前
Flask应用调试模式下外网访问的技巧
后端·python·flask
阮清漪32 分钟前
Bash语言的智能家居
开发语言·后端·golang