打开网易新闻 查看精彩图片

2024年State of JS调研显示,SolidJS的用户留存率高达94%,仅次于Svelte。但让人意外的是,这个"无虚拟DOM"框架的元框架SolidStart,直到最近才被大规模讨论——不是因为新功能,而是有人测完SSR性能后,发现它比Next.js快了将近40%。

这有点像发现你家楼下开了三年的便利店,其实藏着米其林级别的厨房。SolidStart作为SolidJS的官方元框架,把服务端渲染(SSR)、路由、服务器函数打包成开箱即用的工具链。核心卖点就一个:用React式的开发体验,换原生级的运行时性能。

Server Functions:把API端点写成普通函数

Server Functions:把API端点写成普通函数

SolidStart的「服务器函数(Server Functions)」机制,本质上是一种RPC(远程过程调用)的语法糖。你在文件顶部加一行'use server',普通异步函数就变成了可序列化的服务端接口。

代码层面看,这消除了前后端之间的"翻译层"。

传统全栈开发需要定义路由、写控制器、处理序列化。SolidStart让你直接导出函数,框架自动处理HTTP边界。下面这段示例展示了完整的CRUD操作:

import { db } from './db';

export async function getPosts(query?: string) {

return db.posts.findMany({

where: query ? { title: { contains: query } } : undefined,

orderBy: { createdAt: 'desc' },

take: 20,

export async function createPost(title: string, body: string) {

if (!title || !body) throw new Error('Title and body required');

return db.posts.create({ data: { title, body } });

export async function deletePost(id: string) {

return db.posts.delete({ where: { id } });

注意这里的类型安全——TypeScript定义从前端一直透传到数据库层,不需要额外的OpenAPI或tRPC配置。对于习惯了Next.js App Router的开发者,这种"函数即API"的写法会显著减少样板代码。

路由与数据加载:Suspense的另一种实现

路由与数据加载:Suspense的另一种实现

SolidStart的路由系统基于文件约定,但数据加载模式与React生态有明显差异。它用createAsync替代了useEffect + useState的组合,配合SolidJS原生的Suspense实现。

关键区别在于响应式粒度。React的重新渲染以组件为单位,SolidJS则以信号(Signal)为最小更新单元。看这段路由组件代码:

import { createAsync, useSearchParams } from '@solidjs/router';

import { For, Suspense } from 'solid-js';

import { getPosts } from '~/lib/api';

export default function PostsPage() {

打开网易新闻 查看精彩图片

const [params] = useSearchParams();

const posts = createAsync(() => getPosts(params.q));

return (

Posts

Loading...

  • {(post) => (

  • {post.title}

createAsync返回的是响应式引用,而非Promise。当params.q变化时,只有依赖该信号的代码路径会重新执行,而非整个组件树。这种细粒度更新在复杂列表场景下,性能差距会被指数级放大。

For组件是SolidJS的循环原语,与React的map渲染相比,它能复用DOM节点而非销毁重建。配合Suspense的流式HTML传输,首屏时间(FCP)和可交互时间(TTI)都有可测量的提升。

细粒度响应式:为什么能跳过虚拟DOM

细粒度响应式:为什么能跳过虚拟DOM

理解SolidStart的前提,是理解SolidJS的响应式模型。它不依赖虚拟DOM的diff算法,而是在编译阶段将响应式依赖转化为直接的DOM操作指令。

看一个基础计数器示例:

import { createSignal, createMemo, createEffect } from 'solid-js';

export default function Counter() {

打开网易新闻 查看精彩图片

const [count, setCount] = createSignal(0);

const doubled = createMemo(() => count() * 2);

createEffect(() => {

console.log('Count changed:', count());

return (

Count: {count()}

Doubled: {doubled()}

setCount(c => c + 1)}>Increment

createSignal创建响应式状态,createMemo派生计算值,createEffect处理副作用。这三个原语构成了完整的响应式系统。与React Hooks的规则约束(只能在顶层调用、依赖数组手动维护)不同,SolidJS的信号可以随处传递、自由组合。

性能优势来自编译时的静态分析。框架知道每个信号被哪些DOM节点引用,更新时直接定位到具体元素,而非遍历虚拟树。内存占用也因此更低——不需要维护两份DOM表示。

这种架构对服务端渲染有特殊意义。虚拟DOM在服务端是纯粹的计算开销,SolidJS的字符串化渲染路径更短,hydration(注水)阶段需要恢复的交互状态也更少。

API Routes与部署适配

API Routes与部署适配

SolidStart支持混合路由模式:文件约定路由与显式API路由并存。后者适合需要精确控制HTTP语义的场景:

import { json } from '@solidjs/router';

import type { APIEvent } from '@solidjs/start/server';

import { db } from '~/lib/db';

export async function GET(event: APIEvent) {

const posts = await db.posts.findMany({ take: 50 });

return json(posts);

APIEvent对象提供对原始请求的访问,包括headers、cookies和平台特定扩展。部署层面,SolidStart通过Vinxi构建工具抽象了运行时差异,同一套代码可以输出到Node.js、Deno、Cloudflare Workers或Vercel Edge。

这种"边缘优先"的设计思路,与Next.js的edge runtime策略相似,但实现更轻量。没有庞大的客户端hydration bundle,冷启动时间控制在毫秒级。

社区目前的讨论焦点在于生态成熟度。SolidJS的npm周下载量约为React的0.3%,第三方组件库和招聘市场的稀缺性,是技术选型时的真实阻力。但性能敏感型产品(数据可视化、实时协作工具)的开发者,正在把它作为秘密武器。

一个值得玩味的细节:SolidStart的GitHub仓库里,有用户提交了名为"Why is this not more popular?"的issue。维护者的回复很克制——"We're working on it." 这种技术自信与传播焦虑的落差,或许正是小众框架的常态。你会为了40%的性能提升,接受一套全新的响应式心智模型吗?