前端工程师的第一节 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.rsindex.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 第一课。

评论区

0 条评论

登录后可评论。

查看完整榜单
查看完整榜单
查看完整榜单