前端工程师的第一节 Rust 课:从 JavaScript 到 napi-rs,我帮你把第一个 npm 包跑通了
前端工程师的第一节 Rust 课:从 JavaScript 到 napi-rs,我帮你把第一个 npm 包跑通了
导语
你经常听说 SWC、Turbopack、Oxc 这些工具都是 Rust 写的,速度快得离谱。可轮到自己想上手时,一看到所有权、生命周期、编译错误,不少人又缩回去了。这篇文章不聊宏大的“Rust 重构前端工具链”叙事,就从最具体的问题开始:一个前端工程师怎么在不换赛道的前提下,先把 Rust 用起来,并真的产出一个可发布的 npm 包。
正文
问题:前端想碰 Rust,最难的是“第一公里”
大多数前端工程师的日常是 TypeScript、Vite、Webpack、Node.js。想尝试 Rust 时,第一道坎不是语法,而是“我学了之后到底能立刻用在哪儿”。如果没有一个足够小、足够具体、还能立刻验证产出的目标,很容易学了两周所有权规则就放弃。
这不是“要不要学 Rust”的问题,而是“怎么用最小代价跑通第一个闭环”。
方案:先做 npm 包,不做系统
最务实的路线是把 Rust 当成“高性能扩展模块”,而不是整个重写。前端场景里最典型、最容易拿到正反馈的,就是 写一个 JS 能直接调用的 npm 包。这里最成熟的桥接方案就是 napi-rs。
它能帮你做到三件事:
- Rust 侧写业务逻辑,享受静态类型和零成本抽象;
- 自动生成 TypeScript 类型定义;
- 输出 Node.js 原生模块,publish 到 npm 后像普通包一样使用。
对前端工程师来说,这就是最低摩擦入口。
代码:我用 60 行 Rust 写了一个字符串处理工具包
下面这个例子做的是一个非常具体的小工具:给定一段文本,统计词频并返回 top N。这类逻辑放在 JS 里也能做,但 Rust 版本在大量数据下会明显更快,而且类型安全。
先把项目初始化:
npm init -y
npm install -D @napi-rs/cli
npx napi init
这会生成基础工程结构。我们只改 src/lib.rs 和 index.js。
src/lib.rs:
use napi::bindgen_prelude::*;
use std::collections::HashMap;
#[napi]
pub fn top_words(text: String, top: u32) -> Vec {
let mut freq: HashMap = HashMap::new();
for word in text.split_whitespace() {
*freq.entry(word).or_insert(0) += 1;
}
let mut items: Vec = freq.iter().collect();
items.sort_by(|a, b| b.1.cmp(a.1));
items
.iter()
.take(top as usize)
.map(|(k, _)| (*k).to_string())
.collect()
}
index.js:
const { topWords } = require('./index.napi.node');
const text = 'rust js typescript rust rust node npm rust js';
console.log(topWords(text, 3));
// 预期大致返回 ["rust", "js", "typescript"]
构建并验证:
npm run build
node index.js
到这里,你已经拥有一个由 Rust 实现、能被 Node.js 直接调用、并且具备 TypeScript 类型能力的包了。
结论与下一步
对前端工程师来说,Rust 的切入点不该是“全栈换语言”,而应该是“把最慢、最热、最确定性的部分交给 Rust,其余继续留在 JS 生态”。napi-rs 就是当前最成熟的桥梁。
我的建议很简单:
1. 先找一个纯函数型小工具练手,比如词频、校验、编解码;
2. 跑通 Rust 源码、napi-rs 绑定、npm publish 全链路;
3. 再评估团队里哪些 npm 包可以从 JS 迁移到 Rust。
你不需要一开始就做一个“前端工具链大重构”。先把第一个包发布出去,这就是前端工程师最扎实的 Rust 第一课。
评论区
登录后可评论。













