我把我的第一个项目过度工程化:用 Bun 桥接 TypeScript 与 Zig!🚀

发布: (2026年3月16日 GMT+8 10:29)
5 分钟阅读
原文: Dev.to

Source: Dev.to

你好,你好!又是我 Owen!

我已经有一段时间没有活动了,觉得也许该再发点东西了。有些人说编码项目应该从待办清单、REST API、生成器等开始。相反,我直接跳进深水区:我想快速构建一些东西,学习内存管理,并弄清楚不同语言之间是如何通信的。

于是,我创建了 Dunena——一个高性能、混合架构的 monorepo。它利用 BunTypeScript 处理 Web 层,并通过外部函数接口(FFI)将繁重的 CPU 任务委托给 Zig。我还把它部署在 Kubernetes 上(仍在学习 Docker 和 K8s)。

🔗 Dunena Repository on GitHub
🔗 Documentation

什么是 Dunena?

在核心层面,Dunena 是一个后端平台,旨在快速高效地处理请求。它包括路由、WebSockets、发布/订阅服务以及缓存层。

真正的魔法在于底层:我想要 TypeScript 的快速开发速度,但又不希望 Node/Bun 因压缩、布隆过滤器或复杂的统计计算等重计算而变得迟缓。

技术栈

  • 运行时 & 单仓库管理器: Bun 🥟
  • 主要语言: TypeScript (strict mode)
  • 高性能核心: Zig ⚡
  • 数据库: SQLite 🗄️
  • 部署: Docker & Kubernetes 🐳

架构

项目中最酷(也是最吓人)的部分是 FFI 桥接。下面展示了请求如何从 TypeScript 传递到几乎裸金属的 Zig 执行。

Zig 端

// zig/src/exports.zig
const std = @import("std");

// Export a function so Bun can read it via the C ABI
export fn compute_heavy_stats(input_val: i32) i32 {
    // Imagine some incredibly complex, CPU‑blocking math here
    var result = input_val * 42;
    return result;
}

TypeScript 端

// packages/platform/src/bridge/ffi.ts
import { dlopen, FFIType, suffix } from "bun:ffi";

// Load the compiled Zig library
const path = `../../zig/zig-out/lib/libdunena_core.${suffix}`;

const { symbols } = dlopen(path, {
  compute_heavy_stats: {
    args: [FFIType.i32],
    returns: FFIType.i32,
  },
});

// Now I can call Zig directly from TypeScript!
export function runStats(input: number): number {
  return symbols.compute_heavy_stats(input);
}

当客户端访问 Bun 服务器(apps/server/src/index.ts)时,平台负责 API 路由,将繁重的计算交给 Zig 处理,并立即返回结果。

“AI”大象在房间里

我使用 AI 编码代理(Claude、Gemini)来加速样板代码、搭建 monorepo 结构,并搭建初始文件架构。AI 帮我快速推进,但我仍然必须进行残酷的、抓狂的调试和修复:

  • 如果 AI 在 Zig 中更改了数据类型,却忘记在 TypeScript 中更新相应的 FFI 定义,服务器会因内存访问违规而崩溃。
  • 管理指针、防止内存泄漏,以及让 Kubernetes 与附加的 SQLite 卷一起工作,都需要细致的人为监督。

这次经历让我明白,尤其在处理底层系统时,不能盲目信任生成的代码。

最大的挑战

1. 跨越虚空的内存管理

在 TypeScript 与 Zig 之间传递数据没有安全网。Bun 的垃圾回收器对 Zig 的内存管理一无所知,所以我必须学习 Zig 中的手动分配和 defer 语句。

2. Kubernetes 中的 SQLite

通过持久卷声明(Persistent Volume Claims)在 K8s Pod 上部署 SQLite(基于文件的数据库)对单个 Pod 可行,但水平扩展时可能会导致数据库锁定问题。

接下来是什么?

项目远未“完成”。我目前独自维护,但欢迎贡献。未来的想法包括:

  • 使用更安全的抽象来改进 FFI 层。
  • 探索替代存储方案,以实现更好的水平扩展。
  • 添加更多高性能的 Zig 模块(例如图像处理、密码学)。

让我们联系!

我很期待社区的任何反馈、代码审查或建议。

🔗 GitHub 仓库
🔗 文档

你有没有遇到过这样混合语言或与 FFI 边界搏斗的情况?在评论中告诉我吧! 👇

0 浏览
Back to Blog

相关文章

阅读更多 »