大数跨境

Tirne:适用于 Bun、Node、Deno 和 Workers 的明确且受 Go 启发的 Web 框架

Tirne:适用于 Bun、Node、Deno 和 Workers 的明确且受 Go 启发的 Web 框架 索引目录
2025-06-11
0
导读:关注【索引目录】服务号,更多精彩内容等你来探索!“最小”框架正在欺骗你废话少说:Hono 和 Elysia 并不是可扩展的 Web 框架。

关注【索引目录】服务号,更多精彩内容等你来探索!

“最小”框架正在欺骗你

废话少说:Hono 和 Elysia 并不是可扩展的 Web 框架。
它们非常适合用于玩具项目、快速演示和 Hacker News 要点——但如果你曾经尝试在生产级应用中扩展它们,你就会知道其中的痛苦:

  • 隐藏在插件中的中间件逻辑
  • 全球国家混乱
  • 装饰者打破沉默
  • 无法追踪的隐式路由行为

第一天它们看起来很干净。到了第三十天,就变成了无法维护的抽象汤。


时间:功能性、明确性、按比例建造

Tirne是一个 Bun 原生的 Web 框架,由被魔法驱动的工具链所困扰的工程师设计。

我们不想构建一个框架。
我们想在凌晨 2 点停止调试装饰器。

Tirne 从 Go 中汲取灵感net/http— — Go 的功能是一流的,结构是可见的,并且控制权始终掌握在你手中。

// index.ts
import { createRouter, compose, json } from "tirne";

const logger = async (ctx, next) => {
  console.log(`[${ctx.method}] ${ctx.url.pathname}`);
  return await next();
};

const routes = [
  {
    method: "GET",
    path: "/",
    handler: compose([logger], () => json({ hello: "Tirne" })),
  },
];

Bun.serve({ fetch: createRouter(routes) });

就是这样。没有宏。没有命令行界面。没有隐藏行为。它易于扩展,因为它是显式的。 ⭐


Tirne 存在的原因(以及为什么您可能需要它)

  • 因为您不需要阅读框架内部内容来理解处理程序。
  • 因为 Go 风格的错误处理比try/catch体操更安全。
  • 因为路由和中间件应该是函数,而不是链式魔法书。
  • 因为“零样板”不应该意味着“零控制”。
Tirne 是 Go 和 Bun 生下的孩子——由一位讨厌装饰者的后端工程师抚养长大。

真正的比较:Tirne 与 Toys


Axis
Tirne ✨
Hono
Elysia
Structure
✅ Pure data & functions
❌ Chained DSL
❌ Magic macros
Middleware
✅ compose(fn[])
❌ Global spaghetti
❌ Plugin jungle
Type Safety
⚪️ Composable & readable
⚪️ Mediocre
Too heavy, too brittle
Runtime
✅ Bun, Node, Workers, Deno
✅ Mostly
❌ Bun only, not portable
Scaling
✅ Predictable & explicit
❌ Hidden side effects
❌ Framework lock-in


想要规模化?那就先让你的架构变得简单——但又清晰可见。


哲学:没有魔法,只有代码

Tirne 遵循五条不容置疑的规则:

  1. 如果它不能用五行写出来,它可能就不应该存在。
  2. 函数 > 框架。始终如此。
  3. 返回错误。不要抛出错误。
  4. 像大人一样平行奔跑。
  5. 一个文件就足够了。始终如此。
你不需要框架。你需要的是结构。Tirne 就是那个结构。

安装它。使用它。判断它。

包子

bun init
bun add tirne
touch index.ts
//index.ts
import { createRouter, json } from "tirne";

const routes = [
  { method: "GET", path: "/", handler: () => json({ msg: "Hello" }) },
];

Bun.serve({ fetch: createRouter(routes) });
bun run index.ts

德诺

touch index.ts  deno.json
//index.ts
import { createRouter, json } from "https://deno.land/x/tirne@v1.0.2/mod.ts";

const routes = [
  {
    method: "GET",
    path: "/",
    handler: () => json({ message: "Hello from Deno + Tirne!" }),
  },
];

const router = createRouter(routes);
console.log("Server is running on http://localhost:8000");

Deno.serve({ handler: router });
//deno.json
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["deno.ns", "deno.dom","dom"],
    "strict": true
  }
}


deno run --allow-net index.ts

Cloudflare Workers

npm install -g wrangler
wrangler init tirne-worker
cd tirne-worker
npm install tirne
// src/index.ts
import { createRouter, json } from "tirne";

const routes = [
  {
    method: "GET",
    path: "/",
    handler: () => json({ message: "Hello from Tirne on Cloudflare Workers!" }),
  },
];

const router = createRouter(routes);

export default {
  fetch: router,
};
wrangler dev

节点

npm init -y
npm install --save-dev ts-node typescript tirne
touch index.ts
//index.ts
import { createServer, IncomingMessage } from "http";
import { createRouter, json } from "tirne";

const routes = [
  {
    method: "GET",
    path: "/",
    handler: () => json({ message: "Hello from Node.js + Tirne!" }),
  },
];

const router = createRouter(routes);

const server = createServer(async (req, res) => {
  const url = `http://localhost:3000${req.url}`;

  const headers = new Headers(
    Object.entries(req.headers || {})
      .filter(([_, value]) => typeof value === "string")
      .map(([key, value]) => [key, value as string])
  );

    const request = new Request(url, {
      method: req.method,
      headers,
      body: req.method !== "GET" && req.method !== "HEAD" ? await streamToBuffer(req) : undefined,
    });

  async function streamToBuffer(stream: IncomingMessage): Promise<Buffer> {
    const chunks: Buffer[] = [];
    for await (const chunk of stream) {
      chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
    }
    return Buffer.concat(chunks);
  }

  const response = await router(request);


  res.writeHead(response.status, Object.fromEntries(response.headers.entries()));


  const body = await response.text(); //

  res.end(body);
});

server.listen(3000, () => {
  console.log("Server is running on http://localhost:3000");
});

npx ts-node index.ts

关注【索引目录】服务号,更多精彩内容等你来探索!


【声明】内容源于网络
0
0
索引目录
索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
内容 444
粉丝 0
索引目录 索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
总阅读12
粉丝0
内容444