Next.js 风格路由内置?Bun FileSystemRouter 凭啥这么香

82 阅读3分钟
// pages/index.ts
export default () => new Response("首页");
// server.ts
import { FileSystemRouter } from "bun";
const r = new FileSystemRouter({ dir"./pages" });
Bun.serve({
  fetch: async (req) => {
    const m = r.match(req);
    return m ? (await import(m.filePath)).default(req, m) : new Response("404");
  },
});

bun run server.ts 就跑起来了。访问 / 返回"首页"。再加个 pages/about.ts/about 就有了。文件名,就是路由。

图片

痛点:手写路由表,写了十几年

写电商、写 OA、写 CRM。php、java、js、nodejs、bunjs、ts、python,全用过。

每个项目,第一件事就是写路由表:

// express
app.get("/", home);
app.get("/user/:id", user);
app.post("/user", createUser);
app.use("/api", apiRouter);

几十个路由,加一个写一行。改路径名,全局搜替换。拼错一个字母,线上 404。

Next.js 出来后,省事了。pages/about.ts 就是 /about。不用注册,不用配置。

但 Next.js 太重了。react、ssr、webpack、babel...就为个文件路由,整个全家桶拉起来。

bun 给了个轻量选项。

FileSystemRouter 是啥?

bun 内置模块,零依赖。

就是把"文件路径"映射成"URL"。

不绑定 react,不绑定 ssr。不绑定任何框架。

配合 Bun.serve 单独跑。

import { FileSystemRouter } from "bun";

const router = new FileSystemRouter({
  style: "nextjs",
  dir"./pages",
  origin: "https://mydomain.com",
  assetPrefix: "_next/static/",
  fileExtensions: [".ts"".tsx"".js"".jsx"],
});

style 固定 "nextjs",这是唯一支持的风格。dir 是扫描目录,必填。origin 用于拼 src 字段。assetPrefix 是静态资源前缀。fileExtensions 控制识别哪些后缀,默认是常见 web 后缀。

匹配规则:

  • • / → pages/index.ts

  • • /about → pages/about.ts

  • • /user/123 → pages/user/[id].ts

  • • /blog/a/b → pages/blog/[...slug].ts

跟 Next.js 一模一样。

动态路由怎么写?

跟 Next.js 一样,方括号包参数。

目录:

pages/
  index.ts
  user/
    [id].ts
  blog/
    [...slug].ts

[id].ts 是单个参数。[...slug].ts 是通配,吃多级路径。

代码:

// pages/user/[id].ts
export default (_req, params) => {
  return Response.json({
    id: params.id,
    name: `用户${params.id}`,
  });
};

params.id 直接拿到 123

通配:

// pages/blog/[...slug].ts
export default (_req, params) => {
  return Response.json({
    slug: params.slug, // "a/b/c"
  });
};

/blog/a/b/cparams.slug 就是 "a/b/c"

可选通配(双层方括号):

// pages/[[...slug]].ts
export default (_req, params) => {
  return Response.json({
    slug: params.slug ?? "", // 没匹配上时是 undefined
  });
};

/foo/bar 走它,/ 也走它。

新增文件要 reload

路由是在初始化时扫一次。后面加文件、改文件名,必须手动 reload:

import { FileSystemRouter } from "bun";

const router = new FileSystemRouter({
  style: "nextjs",
  dir"./pages",
});

// 加了 pages/new.ts 后,调一下:
router.reload();

Bun.serve({
  fetch: async (req) => {
    const m = router.match(req);
    return m ? (await import(m.filePath)).default(req, m) : new Response("404");
  },
});

自己写个文件 watcher 监听 pages 目录,调 reload() 就行。

完整跑起来

目录结构:

api/
  index.ts
  user/
    [id].ts

api/index.ts

export default () => Response.json({
  name: "api",
  version: "1.0.0",
});

api/user/[id].ts

export default (_req, params) => Response.json({
  id: params.id,
  orders: [],
});

server.ts

import { FileSystemRouter } from "bun";

const r = new FileSystemRouter({
  style: "nextjs",
  dir"./api",
});

Bun.serve({
  port: 3000,
  fetch: async (req) => {
    const m = r.match(req);
    if (!m) return new Response("404", { status: 404 });
    const mod = await import(m.filePath);
    return mod.default(req, m);
  },
});

bun run server.ts,搞定。/api 返回版本信息。/api/user/123 返回用户信息。

零配置,零路由表。

跟 Next.js 比,差啥?

差远了。

Next.js 包含:

  • • 文件路由

  • • react ssr

  • • 静态生成

  • • 图片优化

  • • middleware

  • • api routes

  • • 完整 dev 工具链

FileSystemRouter 只有:

  • • 文件路由

就这一项。

所以别拿它当 Next.js 替代品。

正确用法:

  • • api 服务

  • • bff 层

  • • 边缘函数

  • • 小工具后台

这些场景,不需要 react。一个 bun runtime 全搞定。

启动速度差几百倍。冷启动几毫秒。next.js dev 启动几十秒。

跟 Bun.serve HTML 路由配合

Bun.serve 自己也支持 HTML 路由:

Bun.serve({
  routes: {
    "/": new Response("首页"),
    "/health": new Response("ok"),
  },
});

这是手动写死。FileSystemRouter 是扫文件。

两个能配合:

Bun.serve({
  port: 3000,
  routes: {
    "/health": new Response("ok"),
  },
  fetch: async (req) => {
    const m = router.match(req);
    if (!m) return new Response("404", { status: 404 });
    const mod = await import(m.filePath);
    return mod.default(req, m);
  },
});

固定路由走 routes。文件路由走 fetch。两个不冲突。

写代码小细节

详细参数看 bun 官方文档。

工具而已,对号入座

FileSystemRouter 不是什么银弹。就是一个文件路由的小工具。

不替代 next.js。不替代 nuxt。不替代任何前端框架。

用在合适的场景:

  • • 写个 api 服务

  • • 写个 bff 中间层

  • • 写个边缘函数

  • • 写个内部工具

启动快,配置少,文件即路由。

要 ssr、要 react、要生态链,老老实实 next.js。要轻量、要简单、要快,FileSystemRouter 够用。

工具而已,对号入座。