在现代前端开发中,SolidJS 凭借其极致的细粒度响应式性能,正逐渐成为 React 的有力竞争者。而 SolidStart 作为 Solid 生态下的全栈元框架,不仅继承了这份高性能,更带来了极致的开发体验。
我将从零构建一个 SolidStart SPA(单页应用),并重点剖析其核心功能------文件路由。
1. 背景:为什么用 SolidStart 开发 SPA?
通常提到 SolidStart,大家会联想到 SSR(服务端渲染)。但用它开发 SPA(客户端渲染)同样具有独特优势:
- 极致的性能 :SolidJS 无虚拟 DOM,使用编译时的细粒度响应式系统,这意味着你的 SPA 应用打包体积更小,运行时内存占用更低,更新性能更佳。
- 同构代码的灵活性:虽然输出 SPA,但代码结构依然保持了全栈的规范。如果未来某个页面需要 SEO 或首屏加速,你可以轻松将该路由改为 SSR 模式,无需重构整个项目。
- "真正的"文件路由 :SolidStart 的路由系统不仅仅是路径匹配,它深度集成了懒加载 和代码分割 。这在 SPA 中至关重要,能确保用户首页加载时只下载必要的代码,显著提升首屏加载速度。
简单来说,SolidStart 让你用写全栈应用的架构,去产出性能天花板级别的 SPA。
2. 安装:极速初始化
SolidStart 的官方脚手架非常简洁。如果你要创建一个纯粹的 SPA 项目(即关闭 SSR),可以按以下步骤操作。
打开终端,运行以下命令创建一个新项目:
bash
# 使用 npm
npm create solid@latest my-spa-app
# 或者使用 pnpm (推荐)
pnpm create solid@latest my-spa-app
在交互式选择中,你可以选择 "Blank" 模板或 "Hacker News" 演示模板。对于 SPA 开发,模板选择影响不大。
进入项目目录并安装依赖:
bash
cd my-spa-app
npm install
为了让项目强制输出为 SPA,我们需要进行下一步的配置调整。
3. 配置:开启 SPA 模式
默认情况下,SolidStart 会开启 SSR 以服务端渲染。要将其转换为标准的 SPA,只需修改 app.config.ts 文件。
typescript
// app.config.ts
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({
// 关键配置:关闭 SSR,开启 SPA 模式
ssr: false
});
这意味着什么?
设置 ssr: false 后,构建过程将不再运行服务端渲染逻辑,而是直接生成包含静态 index.html、JS 和 CSS 文件的 dist 目录。这与你使用 Vite 构建 Vue/React SPA 的体验完全一致,但你依然享受 SolidStart 带来的文件路由便利。
4. 核心:文件路由的使用
这是 SolidStart 最让人爱不释手的特性。你不需要手写任何 Route 组件,只需要在 src/routes 目录下创建文件,路由就自动生成了。
我们先来看一下标准的 SPA 中 src/app.tsx 的配置:
typescript
// src/app.tsx
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
import { Suspense } from "solid-js";
export default function App() {
return (
<Router root={(props) => (
// Suspense 是必须的,因为文件路由组件是懒加载的
<Suspense>{props.children}</Suspense>
)}>
{/* 这一行代码替你生成了整个路由表! */}
<FileRoutes />
</Router>
);
}
基础路由映射
文件路径即 URL 路径,这是最直观的部分:
| 文件路径 | 对应 URL | 说明 |
|---|---|---|
src/routes/index.tsx |
/ |
首页入口 |
src/routes/about.tsx |
/about |
关于我们页面 |
src/routes/blog.tsx |
/blog |
博客列表页 |
你不需要手动导入这些组件,FileRoutes 组件会自动收集它们并处理懒加载。
嵌套布局 (Nested Layouts)
这是文件路由的精髓所在。在复杂的 SPA 中,通常不同的模块有不同的布局(例如:首页有 Header,后台管理有侧边栏)。SolidStart 通过文件与文件夹同名的机制来解决。
我们有如下文件结构:
text
routes/
├── about.tsx ( /about )
├── blog.tsx ( /blog 的布局文件)
└── blog/ ( /blog 下的子文件夹)
├── index.tsx ( /blog 的主内容)
└── first-post.tsx ( /blog/first-post )
关键点在于 blog.tsx:
typescript
// src/routes/blog.tsx
import { Outlet } from "@solidjs/router";
export default function BlogLayout() {
return (
<div>
<h1>博客导航栏</h1>
{/* 类似 Vue Router 的 <router-view />,这里将渲染 index.tsx 或 first-post.tsx */}
<Outlet />
<footer>博客底部版权</footer>
</div>
);
}
当用户访问 /blog/first-post 时,渲染逻辑是:
这种结构非常适合 SPA 开发,因为它允许你在切换子路由时,复用父级布局的 DOM 元素和状态,无需重复渲染整个页面。
索引路由 (Index Routes)
如果你有一个文件夹(如 /settings),想要有一个默认页面(如 /settings 本身),你需要使用 index.tsx:
text
routes/
└── settings/
├── index.tsx (对应 /settings )
└── profile.tsx (对应 /settings/profile )
5. 开发体验:极致的流畅感
SolidStart 结合了 Vite 作为底层工具链,这使得开发体验非常现代化:
1. 热模块替换 (HMR)
由于 Vite 的加持,当你修改路由组件中的样式或 JSX 逻辑时,页面状态几乎能够瞬间保留并刷新。这种响应速度在大型 SPA 项目中能显著提升开发效率。
2. 明确的路由结构
在传统的 React SPA 中,如果你有一个大型应用,react-router 的配置表可能会变得极其臃肿(成千上万行)。但在 SolidStart 中,看一眼 src/routes 文件夹,项目的页面结构一目了然。文件夹即导航,极大地降低了新成员上手项目的认知负担。
3. API 路由也是 SPA 的后盾
虽然是 SPA,但你依然可以在 src/routes/api 下编写后端函数。
typescript
// src/routes/api/hello.ts
import type { APIEvent } from "solid-start";
export const GET = async (event: APIEvent) => {
return new Response(JSON.stringify({ message: "Hello from SPA backend" }), {
headers: { "Content-Type": "application/json" }
});
};
在前端,你可以直接用 fetch("/api/hello") 调用它。这让你在开发 SPA 时,无需单独启动 Mock 服务器或配置代理,直接拥有全栈能力。
4. 类型安全
<FileRoutes /> 是类型安全的。配合 @solidjs/router 的 Hooks(如 useParams、useNavigate),你可以获得精准的路径参数提示,减少因路由拼写错误导致的低级 Bug。
总结
使用 SolidStart 开发 SPA,你得到的不仅是一个高性能的 SolidJS 应用,更是一套优雅、可扩展且约定优于配置的开发范式。
- 告别 :手写冗余的
<Routes>配置、维护路由表的痛苦、手动懒加载的繁琐。 - 拥抱:基于文件夹的直观结构、开箱即用的代码分割、以及随时可切换渲染模式的全栈灵活性。
如果你正准备开始一个新的 SolidJS 项目,不妨直接试试 SolidStart------即使你只开启 SPA 模式,它也会让你对"框架"有一个全新的认识。