大家好,我是农村程序员,独立开发者,行业观察员,前端之虎陈随易。
- 关注公众号:
陈随易
,获取最新观察和思考。 - 个人网站 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 设计中的遗憾,那么后来者 Deno
和 Bun
解决了这些问题了吗?同样很遗憾地告诉你,无法解决,只能妥协,只能打补丁。
因为 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 操作不用再额外安装第三方依赖了。
不过目前仅支持 PostgreSQL
,Mysql
将在后续支持。
静态存储协议
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 生态。
关注公众号,分享更多技术观察和思考。