VOOZH about

URL: https://dev.to/0012303/solidstart-has-a-free-framework-server-side-rendering-with-fine-grained-reactivity-5c25

⇱ SolidStart Has a Free Framework: Server-Side Rendering with Fine-Grained Reactivity - DEV Community


Why SolidStart?

SolidStart is the meta-framework for SolidJS - the UI library with fine-grained reactivity that skips the virtual DOM entirely. If you want React-like DX with significantly better runtime performance, SolidStart gives you SSR, routing, and server functions out of the box.

Quick Start

npm init solid@latest my-app
cd my-app
npm install
npm run dev

Server Functions (RPC)

// src/lib/api.ts
'use server';

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 } });
}

Routes with Data Loading

// src/routes/posts/index.tsx
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 (
 <div>
 <h1>Posts</h1>
 <form method="get">
 <input name="q" value={params.q || ''} placeholder="Search..." />
 </form>
 <Suspense fallback={<p>Loading...</p>}>
 <ul>
 <For each={posts()}>
 {(post) => (
 <li>
 <a href={`/posts/${post.id}`}>{post.title}</a>
 </li>
 )}
 </For>
 </ul>
 </Suspense>
 </div>
 );
}

Fine-Grained Reactivity

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 (
 <div>
 <p>Count: {count()}</p>
 <p>Doubled: {doubled()}</p>
 <button onClick={() => setCount(c => c + 1)}>Increment</button>
 </div>
 );
}

API Routes

// src/routes/api/posts.ts
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);
}

export async function POST(event: APIEvent) {
 const body = await event.request.json();
 const post = await db.posts.create({ data: body });
 return json(post, { status: 201 });
}

Middleware

// src/middleware.ts
import { createMiddleware } from '@solidjs/start/middleware';

export default createMiddleware({
 onRequest: [
 (event) => {
 const start = Date.now();
 event.locals.startTime = start;
 },
 ],
 onBeforeResponse: [
 (event) => {
 const duration = Date.now() - event.locals.startTime;
 console.log(`${event.request.method}${event.request.url} - ${duration}ms`);
 },
 ],
});

Real-World Use Case

A fintech startup needed a dashboard that updates hundreds of data points in real-time. React re-rendered entire component trees on each WebSocket message. SolidStart with fine-grained reactivity only updates the exact DOM nodes that changed. Result: 60fps even with 500+ live-updating cells, and bundle size dropped 40%.


Building reactive apps? I create custom data pipelines and automation tools. Check out my web scraping toolkit on Apify or reach me at spinov001@gmail.com for custom solutions.