Awesome-omni-skill solidstart-entrypoints
SolidStart entrypoints: app.tsx for isomorphic root, entry-client.tsx for browser initialization, entry-server.tsx for SSR setup, app.config.ts for build configuration.
install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/frontend/solidstart-entrypoints" ~/.claude/skills/diegosouzapw-awesome-omni-skill-solidstart-entrypoints && rm -rf "$T"
manifest:
skills/frontend/solidstart-entrypoints/SKILL.mdsource content
SolidStart Entrypoints
Complete guide to customizing SolidStart entrypoints. Entrypoints control how your app initializes on both client and server.
app.tsx - Isomorphic Root
The
App component is the isomorphic (shared on server and browser) entry point. This is where code runs on both sides.
Basic Example (with Routing)
import { A, Router } from "@solidjs/router"; import { FileRoutes } from "@solidjs/start/router"; import { Suspense } from "solid-js"; export default function App() { return ( <Router root={(props) => ( <> <nav> <A href="/">Index</A> <A href="/about">About</A> </nav> <Suspense>{props.children}</Suspense> </> )} > <FileRoutes /> </Router> ); }
Critical: Always wrap router root with
<Suspense> - routes are lazy-loaded.
Bare Example (no routing)
export default function App() { return ( <main> <h1>Hello world!</h1> </main> ); }
Key points:
- Runs on both server and client
- Define router setup here
- Add global layouts, providers, context
- Shared initialization logic
entry-client.tsx - Browser Entry
entry-client.tsx is where the application starts in the browser. It mounts the app to the DOM.
Basic Setup
import { mount, StartClient } from "@solidjs/start/client"; mount(() => <StartClient />, document.getElementById("app")!);
Custom Client Initialization
import { mount, StartClient } from "@solidjs/start/client"; // Register service workers if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js"); } // Client-only initialization console.log("Client starting"); mount(() => <StartClient />, document.getElementById("app")!);
Use cases:
- Service worker registration
- Client-only initialization
- Browser API setup
- Analytics initialization
- Client-side routing setup
Important: This file runs only in the browser, not on the server.
entry-server.tsx - Server Entry
entry-server.tsx is where the application starts on the server. It defines the HTML document structure.
Basic Setup
import { createHandler, StartServer } from "@solidjs/start/server"; export default createHandler(() => ( <StartServer document={({ assets, children, scripts }) => ( <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> {assets} </head> <body> <div id="app">{children}</div> {scripts} </body> </html> )} /> ));
Custom Document Structure
import { createHandler, StartServer } from "@solidjs/start/server"; export default createHandler(() => ( <StartServer document={({ assets, children, scripts }) => ( <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="description" content="My SolidStart app" /> <link rel="icon" href="/favicon.ico" /> <link rel="stylesheet" href="/styles.css" /> {assets} </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="app">{children}</div> {scripts} </body> </html> )} /> ));
SSR Modes
Configure SSR mode in
createHandler:
import { createHandler, StartServer } from "@solidjs/start/server"; // Sync SSR (default) export default createHandler(() => <StartServer document={...} />); // Async SSR export default createHandler( () => <StartServer document={...} />, { mode: "async" } ); // Streaming SSR export default createHandler( () => <StartServer document={...} />, { mode: "stream" } );
Document props:
: CSS and other asset linksassets
: Rendered app contentchildren
: JavaScript bundlesscripts
app.config.ts - Build Configuration
The
app.config.ts is the root configuration file for SolidStart, Vinxi, Vite, and Nitro.
Basic Configuration
import { defineConfig } from "@solidjs/start/config"; export default defineConfig({});
Advanced Configuration
import { defineConfig } from "@solidjs/start/config"; export default defineConfig({ server: { preset: "node-server", // or "vercel", "netlify", etc. }, vite: { // Vite configuration build: { target: "esnext", }, }, nitro: { // Nitro configuration preset: "node-server", }, });
Configuration options:
: Server preset and settingsserver
: Vite build configurationvite
: Nitro server configurationnitro
: Router configurationrouter
: SSR mode settingsssr
Common Patterns
Adding Global Providers
// app.tsx import { Router } from "@solidjs/router"; import { FileRoutes } from "@solidjs/start/router"; import { Suspense } from "solid-js"; import { ThemeProvider } from "./contexts/ThemeContext"; export default function App() { return ( <ThemeProvider> <Router root={(props) => <Suspense>{props.children}</Suspense>}> <FileRoutes /> </Router> </ThemeProvider> ); }
Custom Error Boundaries
// app.tsx import { ErrorBoundary } from "solid-js"; import { Router } from "@solidjs/router"; import { FileRoutes } from "@solidjs/start/router"; export default function App() { return ( <ErrorBoundary fallback={(err) => <div>Error: {err.toString()}</div>}> <Router root={(props) => <Suspense>{props.children}</Suspense>}> <FileRoutes /> </Router> </ErrorBoundary> ); }
Service Worker Registration
// entry-client.tsx import { mount, StartClient } from "@solidjs/start/client"; if ("serviceWorker" in navigator) { window.addEventListener("load", () => { navigator.serviceWorker .register("/sw.js") .then((registration) => { console.log("SW registered:", registration); }) .catch((error) => { console.log("SW registration failed:", error); }); }); } mount(() => <StartClient />, document.getElementById("app")!);
Custom HTML Document
// entry-server.tsx import { createHandler, StartServer } from "@solidjs/start/server"; export default createHandler(() => ( <StartServer document={({ assets, children, scripts }) => ( <html lang="en" data-theme="dark"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>My App</title> <link rel="icon" href="/favicon.ico" /> <link rel="preconnect" href="https://fonts.googleapis.com" /> {assets} </head> <body> <div id="app">{children}</div> {scripts} </body> </html> )} /> ));
Environment-Specific Configuration
// app.config.ts import { defineConfig } from "@solidjs/start/config"; export default defineConfig({ server: { preset: process.env.NODE_ENV === "production" ? "node-server" : "node-dev", }, vite: { server: { port: process.env.PORT ? parseInt(process.env.PORT) : 3000, }, }, });
File Structure
src/ ├── app.tsx # Isomorphic root component ├── entry-client.tsx # Browser entry point ├── entry-server.tsx # Server entry point app.config.ts # Build configuration
Best Practices
-
Keep app.tsx isomorphic:
- Don't use browser-only APIs
- Use
checks if neededisServer - Shared logic only
-
Client-only code in entry-client.tsx:
- Service workers
- Browser APIs
- Client-side analytics
-
Server-only code in entry-server.tsx:
- HTML document structure
- Meta tags
- Server-side initialization
-
Configuration in app.config.ts:
- Build settings
- Server presets
- Vite/Nitro config
-
Always wrap router with Suspense:
- Routes are lazy-loaded
- Suspense handles loading states
Summary
- app.tsx: Isomorphic root, router setup, global providers
- entry-client.tsx: Browser initialization, service workers
- entry-server.tsx: HTML document structure, SSR setup
- app.config.ts: Build and server configuration