随着Node.js的持续演进,一个明显的趋势是:许多过去必须依赖第三方npm包才能实现的功能,如今已被直接集成到运行时中。这一转变不仅帮助开发者精简项目依赖、降低供应链安全风险,还提升了代码的可移植性和可维护性。本文将详细介绍15个最新的Node.js原生特性,它们正在或即将替代那些我们曾经熟悉的npm包。
1. 全局 fetch() 替代 node-fetch
过去:在服务端发起HTTP请求,需要安装 node-fetch 包。
现在:自Node.js 18起,与浏览器标准一致的 fetch() 函数已成为全局API,无需额外引入。
const res = await fetch('https://api.github.com/repos/nodejs/node');
const data = await res.json();
console.log(data.full_name); // "nodejs/node"
- 引入版本:Node.js v18.0.0(稳定)。
- 兼容性提示:若项目需支持Node.js 18以下版本,仍需使用
node-fetch。
2. 全局 WebSocket 客户端
过去:创建WebSocket客户端通常使用 ws 包。
现在:Node.js 21+ 提供了全局的 WebSocket 类,可用于建立客户端连接。
const ws = new WebSocket('wss://echo.websocket.org');
ws.onopen = () => ws.send('Hello!');
ws.onmessage = (event) => console.log('Received:', event.data);
- 当前状态:实验性功能(Node.js v21.0.0引入)。
- 服务端选择:实现WebSocket服务端,
ws 库或其衍生品仍是主流。
3. 内置测试模块 node:test
过去:编写单元测试需依赖Mocha、Jest等第三方框架。
现在:Node.js内置了 node:test 模块,足以满足基础的测试需求。
import test from 'node:test';
import assert from 'node:assert';
test('addition works', () => {
assert.strictEqual(2 + 2, 4);
});
- 稳定版本:Node.js v20.0.0。
- 框架优势:如需快照测试、复杂Mock或丰富的插件生态,第三方测试框架如Jest仍有其价值。
4. 实验性 node:sqlite 模块
过去:操作SQLite数据库常用 sqlite3 或 better-sqlite3,它们依赖本地编译,常出现版本兼容问题。
现在:Node.js正在引入实验性的 node:sqlite 模块,旨在提供开箱即用的SQLite支持。
import { open } from 'node:sqlite';
const db = await open(':memory:');
await db.exec('CREATE TABLE users (id INTEGER, name TEXT)');
5. util.styleText() 替代 chalk
过去:命令行输出彩色文本,chalk 是首选。
现在:Node.js原生提供了 util.styleText() 方法。
import { styleText } from 'node:util';
console.log(styleText('red', 'Error!'));
console.log(styleText(['bold', 'green'], 'Success!'));
6. util.stripVTControlCharacters() 清理ANSI字符
过去:清理日志中的ANSI转义字符需使用 strip-ansi。
现在:Node.js内置了 util.stripVTControlCharacters() 方法。
import { stripVTControlCharacters } from 'node:util';
const text = '\u001B[4mUnderlined\u001B[0m';
console.log(stripVTControlCharacters(text)); // "Underlined"
7. fs.glob() 文件匹配
过去:文件路径模式匹配依赖 glob 包。
现在:Node.js 22+ 的 fs 模块新增了 fs.glob() 方法。
import fs from 'node:fs/promises';
const files = await fs.glob('**/*.js');
console.log(files);
- 稳定版本:Node.js v22.17.0 LTS。
8. fs.rm() 递归删除目录
过去:递归删除目录需要安装 rimraf。
现在:fs.rm() 方法通过 { recursive: true } 选项原生支持。
import fs from 'node:fs/promises';
await fs.rm('dist', { recursive: true, force: true });
9. fs.mkdir() 递归创建目录
过去:创建多级目录需要 mkdirp。
现在:fs.mkdir() 方法的 { recursive: true } 选项可实现相同功能。
await fs.mkdir('logs/app', { recursive: true });
10. crypto.randomUUID() 生成UUID
过去:生成UUID需要 uuid 包。
现在:crypto 模块提供了 randomUUID() 方法。
import { randomUUID } from 'node:crypto';
console.log(randomUUID());
11. 全局 atob() / btoa() 与 Buffer
过去:Base64编码解码需要polyfill包。
现在:全局 atob、btoa 及 Buffer 类已原生支持。
const encoded = btoa('hello');
console.log(encoded); // "aGVsbG8="
console.log(atob(encoded)); // "hello"
12. 全局 URLPattern(实验性)
过去:URL模式匹配使用 url-pattern 包。
现在:Node.js支持Web标准的 URLPattern API。
const pattern = new URLPattern({ pathname: '/users/:id' });
const match = pattern.exec('/users/42');
console.log(match.pathname.groups.id); // "42"
- 当前状态:实验性功能(Node.js v20.0.0引入)。
13. --env-file 标志加载环境变量
过去:加载 .env 文件需安装 dotenv。
现在:Node.js可通过 --env-file 标志直接加载环境文件。
node --env-file=.env app.js
- 当前状态:实验性功能(Node.js v20.10.0引入)。
14. 全局 EventTarget
过去:使用Web标准的EventTarget需要 event-target-shim。
现在:EventTarget 已成为Node.js的全局对象,与浏览器一致。
const target = new EventTarget();
target.addEventListener('ping', () => console.log('pong'));
target.dispatchEvent(new Event('ping'));
15. 实验性TypeScript支持
过去:运行 .ts 文件需要 ts-node 或配置完整的TypeScript编译链。
现在:Node.js提供了实验性的TypeScript直接执行能力(仅剥离类型)。
node --experimental-strip-types app.ts
总结
Node.js正积极地将成熟的社区实践吸收为核心能力。拥抱这些原生特性,能有效减少外部依赖、规避潜在的安全漏洞,并写出更具一致性的代码。对于新项目,尤其是基于Node.js 18/20/22 LTS版本的项目,建议优先考虑这些原生方案。当然,在复杂的生产环境中,仍需根据性能、功能完备性和团队习惯来权衡选择。