Chapter 09

SolidStart 全栈开发

SolidJS 的元框架:文件系统路由、Server Functions、SSR/SSG,一个框架全搞定

1. SolidStart 简介与创建项目

SolidStart 是 SolidJS 的官方元框架(类似 Next.js 之于 React,Nuxt 之于 Vue)。它在 SolidJS 的基础上增加了:

# 创建 SolidStart 项目
pnpm create solid
# 选择 "with-server-functions" 模板

# 或使用官方模板
npm create @solidjs/start

项目结构

my-app/
├── src/
│   ├── routes/           # 文件系统路由
│   │   ├── index.tsx     # → /
│   │   ├── about.tsx     # → /about
│   │   ├── blog/
│   │   │   ├── index.tsx # → /blog
│   │   │   └── [slug].tsx# → /blog/:slug
│   │   └── api/
│   │       └── users.ts  # → /api/users(API Route)
│   ├── app.tsx           # 根布局
│   └── entry-server.tsx  # SSR 入口
├── app.config.ts         # SolidStart 配置
└── package.json

2. 文件系统路由

// src/routes/blog/[slug].tsx
import { useParams } from "@solidjs/router";

export default function BlogPost() {
  const params = useParams();

  return (
    <article>
      <h1>文章:{params.slug}</h1>
    </article>
  );
}

// 特殊路由文件:
// [param]      — 动态路由参数
// [...rest]    — 捕获剩余路径(catch-all)
// (group)      — 路由分组(不影响 URL)
// _layout.tsx  — 嵌套布局

3. Server Functions("use server")

Server Functions 是 SolidStart 最核心的特性。通过在函数顶部添加 "use server" 指令,该函数只在服务端执行,可以直接访问数据库、文件系统等服务端资源:

// src/routes/todos.tsx
import { createServerAction$, createServerData$ } from "solid-start/server";
import { db } from "~/lib/db";

// 服务端数据获取(配合 createResource 使用)
export function routeData() {
  return createServerData$(
    async (): Promise<Todo[]> => {
      "use server"; // 这行代码只在服务端执行
      return await db.todo.findMany();
    }
  );
}

export default function Todos() {
  const todos = useRouteData<typeof routeData>();

  // createServerAction$:创建服务端表单 Action
  const [addTodo, { Form }] = createServerAction$(
    async (formData: FormData) => {
      "use server";
      const text = formData.get("text") as string;
      await db.todo.create({ data: { text, done: false } });
    }
  );

  return (
    <div>
      <Suspense fallback={<p>加载中...</p>}>
        <For each={todos()}>
          {(todo) => <p>{todo.text}</p>}
        </For>
      </Suspense>

      {/* Form 自动处理提交和状态 */}
      <Form>
        <input name="text" placeholder="新任务..." />
        <button type="submit">添加</button>
      </Form>
    </div>
  );
}

4. API Routes

// src/routes/api/users.ts — REST API 端点
import { json } from "solid-start";
import { db } from "~/lib/db";

// GET /api/users
export async function GET() {
  const users = await db.user.findMany();
  return json(users);
}

// POST /api/users
export async function POST({ request }: { request: Request }) {
  const body = await request.json();
  const user = await db.user.create({ data: body });
  return json(user, { status: 201 });
}

// src/routes/api/users/[id].ts
export async function DELETE({ params }: { params: { id: string } }) {
  await db.user.delete({ where: { id: params.id } });
  return new Response(null, { status: 204 });
}

5. SSR / SSG / SPA 模式切换

// app.config.ts
import { defineConfig } from "@solidjs/start/config";

export default defineConfig({
  server: {
    // 渲染模式(在 SolidStart 1.x 中按需配置)
    preset: "vercel", // "node", "cloudflare", "static", "netlify"
  },
  vite: {
    ssr: {
      // SSR 相关配置
    }
  }
});
模式描述适用场景
SSR服务端实时渲染动态内容、实时数据、SEO 要求高
SSG构建时预渲染静态 HTML博客、文档、内容不经常变化
SPA纯客户端单页应用内部工具、需要登录的应用
ISR增量静态再生电商、新闻(静态+按需更新)

6. 认证实现

// src/lib/auth.ts — 基于 Session 的认证
import { useSession } from "vinxi/http";

export async function getSession() {
  "use server";
  return useSession({
    password: process.env.SESSION_SECRET!,
  });
}

export async function login(email: string, password: string) {
  "use server";
  const user = await db.user.findFirst({ where: { email } });
  if (!user || !await bcrypt.compare(password, user.passwordHash)) {
    throw new Error("邮箱或密码错误");
  }
  const session = await getSession();
  await session.update({ userId: user.id });
  return redirect("/");
}

7. 部署到 Vercel / Cloudflare

# 部署到 Vercel
# app.config.ts: preset: "vercel"
pnpm build
vercel deploy

# 部署到 Cloudflare Workers
# app.config.ts: preset: "cloudflare"
pnpm build
wrangler deploy

# 生成静态网站(SSG)
# app.config.ts: preset: "static"
pnpm build
# 输出到 dist/ 目录,可部署到任何静态托管服务
ℹ️

SolidStart 的设计哲学:SolidStart 借鉴了 Remix 的 Server Functions 设计,将服务端和客户端代码写在同一个文件中,编译器自动分离。这比 Next.js 的 getServerSideProps 更自然,比 tRPC 更简单,是全栈 Web 开发的新范式。

本章小结:SolidStart 是 SolidJS 的全栈元框架,提供文件系统路由、Server Functions("use server")、API Routes、多种渲染模式。Server Functions 让前后端代码共存一个文件成为可能,编译器自动处理边界,是构建全栈 SolidJS 应用的首选。