From c83f95728945f1d2ae4a6b078a071361569e5c06 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Mon, 20 Oct 2025 18:34:26 +0200 Subject: [PATCH 1/9] expand docs on rendering modes --- .../building-your-application/data.json | 1 + .../rendering-modes.mdx | 95 +++++++++++++++++++ .../reference/config/define-config.mdx | 39 ++++---- .../reference/entrypoints/entry-server.mdx | 9 +- .../reference/server/create-handler.mdx | 36 ++++--- 5 files changed, 143 insertions(+), 37 deletions(-) create mode 100644 src/routes/solid-start/building-your-application/rendering-modes.mdx diff --git a/src/routes/solid-start/building-your-application/data.json b/src/routes/solid-start/building-your-application/data.json index 2da1baa8d..d68a4b9c2 100644 --- a/src/routes/solid-start/building-your-application/data.json +++ b/src/routes/solid-start/building-your-application/data.json @@ -1,6 +1,7 @@ { "title": "Building your application", "pages": [ + "rendering-modes.mdx", "routing.mdx", "api-routes.mdx", "css-and-styling.mdx", diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx new file mode 100644 index 000000000..2a989e54d --- /dev/null +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -0,0 +1,95 @@ +--- +title: "Rendering Modes" +--- + +SolidStart has 3 kinds of rendering modes: `sync`, `async`, and `stream`. +Let's talk about how each of them work and which one to pick. + +:::note +Default is **stream** and performance-wise should be preferred as a rule-of-thumb. +::: + +All modes have some degree of Server-Side Rendering, you may need to change them globally depending on your deployment provider. +And you may prefer to override them for better bot support and SEO. + +## Impacted Features + +| Feature | sync | async | stream | +| -------------------- | ----------- | --------------------------- | ----------------------- | +| Data fetching | Client-side | Server-side (blocking) | Server-side (streaming) | +| Suspense fallbacks | Yes | No | Yes | +| Time to first byte | Fast | Slower (waits for all data) | Faster | +| Total page load time | Slower | Fast (server fetches) | Faster (progressive) | + +### Sync Mode + +Uses [`renderToString`](/reference/rendering/render-to-string) to render the page from Solid's core to render the page synchronously. +All async features are disabled and the page is rendered as soon as possible and sent to the client-side where data fetching will happen post-hydration. + +### Async Mode + +Uses [`renderToStringAsync`](/reference/rendering/render-to-string-async) to render the page from Solid's core to render the page asynchronously. +All Suspense boundares are resolved and rendered before being sent to the client-side. + +No suspense fallbacks are shown in the browser, which makes this mode ideal for SEO optimizations and bot support. + +### Stream Mode + +Uses [`renderToStream`](/reference/rendering/render-to-stream) to render the page from Solid's core to render the page streaming. +Leveraging [TransformableStream](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) to progressively send the HTML to the client-side. + +This mode is ideal for performance and future-friendly apps. . + +## Global Configuration + +The modes can be defined app-wide via the configuration file or via the [`entry-server.tsx`](/solid-start/reference/entrypoints/entry-server) file. + +```tsx title="app.config.ts" +import { defineConfig } from "@solidjs/start/config"; + +export default defineConfig({ + mode: "stream", +}); +``` + +The value in [`entry-server.tsx`](/solid-start/reference/entrypoints/entry-server) overrides the value in [`app.config.ts`](/solid-start/reference/entrypoints/app-config). + +```tsx title="src/entry-server.tsx" +import { createHandler, StartServer } from "@solidjs/start/server"; + +export default createHandler(() => ( + +), { + mode: "async" +}); +``` + +## Per-Route Configuration + +The optional secondary parameter in [`createHandler`](/solid-start/reference/server/create-handler) can be an object or a function that receives the `RequestEvent` and returns an object with the mode to use for the route. + +```tsx title="src/entry-server.tsx" +import { createHandler, StartServer } from "@solidjs/start/server"; + +export default createHandler(() => ( + +), { + mode: (event) => { + return event.request.url.includes("/special-route") ? "async" : "stream"; + } +}); +``` + +It can also be used for bot detection via the `userAgent` property of the `RequestEvent`. + +```tsx title="src/entry-server.tsx" +import { createHandler, StartServer } from "@solidjs/start/server"; + +export default createHandler(() => ( + +), { + mode: (event) => { + return isBot(event.request.userAgent) ? "async" : "stream"; + } +}); +``` diff --git a/src/routes/solid-start/reference/config/define-config.mdx b/src/routes/solid-start/reference/config/define-config.mdx index 5ba824c13..96974e266 100644 --- a/src/routes/solid-start/reference/config/define-config.mdx +++ b/src/routes/solid-start/reference/config/define-config.mdx @@ -21,11 +21,12 @@ export default defineConfig({ }); ``` -The `vite` option can also be a function that can be customized for each Vinxi router. +The `vite` option can also be a function that can be customized for each Vinxi router. In SolidStart, 3 routers are used: + - `server` - server-side routing -- `client` - for the client-side routing +- `client` - for the client-side routing - `server-function` - server functions. ```tsx @@ -44,11 +45,11 @@ export default defineConfig({ ## Configuring Nitro -SolidStart uses [Nitro](https://nitro.build/) to run on a number of platforms. -The `server` option exposes some Nitro options including the build and deployment presets. +SolidStart uses [Nitro](https://nitro.build/) to run on a number of platforms. +The `server` option exposes some Nitro options including the build and deployment presets. An overview of all available presets is available in the [Deploy section of the Nitro documentation](https://nitro.build/deploy). - Some common ones include: +Some common ones include: **Servers** @@ -85,7 +86,7 @@ export default defineConfig({ #### Special note -SolidStart uses async local storage. +SolidStart uses async local storage. Netlify, Vercel, and Deno support this out of the box but if you're using Cloudflare you will need to specify the following: ```js @@ -103,22 +104,22 @@ export default defineConfig({ Within `wrangler.toml` you will need to enable node compatibility: - ``` compatibility_flags = [ "nodejs_compat" ] ``` ## Parameters -| Property | Type | Default | Description | -| -------------------- | ------------------------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ssr | boolean | true | Toggle between client and server rendering. | -| solid | object | | Configuration object for [vite-plugin-solid](https://github.com/solidjs/vite-plugin-solid) | -| extensions | string[] | ["js", "jsx", "ts", "tsx"] | Array of file extensions to be treated as routes. | -| server | object | | Nitro server config options | -| appRoot | string | "./src" | The path to the root of the application. | -| routeDir | string | "./routes" | The path to where the routes are located. | -| middleware | string | | The path to an optional [middleware](/solid-start/advanced/middleware) file. | -| devOverlay | boolean | true | Toggle the dev overlay. | -| experimental.islands | boolean | false | Enable "islands" mode. | -| vite | `ViteConfig` or `({ router })=>ViteConfig` | | [Vite config object](https://vitejs.dev/config/shared-options.html). Can be configured for each `router` which has the string value "server", "client" or "server-function"` | +| Property | Type | Default | Description | +| -------------------- | ------------------------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ssr | boolean | true | Toggle between client and server rendering. | +| mode | stream, async, sync | stream | The rendering mode to use. | +| solid | object | | Configuration object for [vite-plugin-solid](https://github.com/solidjs/vite-plugin-solid) | +| extensions | string[] | js, jsx, ts, tsx | Array of file extensions to be treated as routes. | +| server | object | | Nitro server config options | +| appRoot | string | "./src" | The path to the root of the application. | +| routeDir | string | "./routes" | The path to where the routes are located. | +| middleware | string | | The path to an optional [middleware](/solid-start/advanced/middleware) file. | +| devOverlay | boolean | true | Toggle the dev overlay. | +| experimental.islands | boolean | false | Enable "islands" mode. | +| vite | `ViteConfig` or `({ router })=>ViteConfig` | | [Vite config object](https://vitejs.dev/config/shared-options.html). Can be configured for each `router` which has the string value "server", "client" or "server-function"` | diff --git a/src/routes/solid-start/reference/entrypoints/entry-server.mdx b/src/routes/solid-start/reference/entrypoints/entry-server.mdx index ba9e09adf..01b85e7c9 100644 --- a/src/routes/solid-start/reference/entrypoints/entry-server.mdx +++ b/src/routes/solid-start/reference/entrypoints/entry-server.mdx @@ -2,11 +2,12 @@ title: entry-server.tsx --- -`entry-server.tsx` is where an application starts on the server. +This is where application is rendered on the server. This happens by `entry-server.tsx` providing a document component to [``](/solid-start/reference/server/start-server) and passing it into [`createHandler`](/solid-start/reference/server/create-handler) for server side rendering. - A typical `entry-server.tsx` for a new project looks like this: -```tsx +Every SolidStart app must have an `entry-server.tsx` file, the most basic usage looks about the following example: + +```tsx title="src/entry-server.tsx" import { createHandler, StartServer } from "@solidjs/start/server"; export default createHandler(() => ( @@ -29,4 +30,4 @@ export default createHandler(() => ( )); ``` -For setting different SSR modes (sync | async | stream), see [`createHandler`](/solid-start/reference/server/create-handler). +To take full advantage of the `entry-server.tsx` file, check the [`createHandler` docs](/solid-start/reference/server/create-handler) and the [Rendering Modes](/solid-start/building-your-application/rendering-modes) page. diff --git a/src/routes/solid-start/reference/server/create-handler.mdx b/src/routes/solid-start/reference/server/create-handler.mdx index 1bf21a54d..fc8c451f9 100644 --- a/src/routes/solid-start/reference/server/create-handler.mdx +++ b/src/routes/solid-start/reference/server/create-handler.mdx @@ -3,28 +3,36 @@ title: createHandler --- The `createHandler` is used to start the server in [`entry-server.tsx`](/solid-start/reference/entrypoints/entry-server). -It takes a function that returns a static document (often created with [``](/solid-start/reference/server/start-server)), and serves it using one of the three function for server side rendering (SSR): +It takes a function that returns a static document (often created with [``](/solid-start/reference/server/start-server)), renders, and serves it. -- [`renderToString`](/reference/rendering/render-to-string) - "sync" -- [`renderToStringAsync`](/reference/rendering/render-to-string-async) - "async" -- [`renderToStream`](/reference/rendering/render-to-stream) - "stream" +:::note +To fully understand how to leverage different rendering modes, please refer to the [Rendering Modes](/solid-start/building-your-application/rendering-modes) page. +::: -The SSR mode can be configured through the `mode` property on the options object: +A `createHandler` is essential to every SolidStart app. +To fallback the rendering mode to the [`app.config.ts`](/solid-start/reference/entrypoints/app-config-ts) definition (or the default "stream" mode), you can use the `createHandler` without any options. -```tsx +```tsx title="src/entry-server.tsx" import { createHandler, StartServer } from "@solidjs/start/server"; export default createHandler(() => ( -), { - mode: "async" -}); +)); ``` -## Parameters +It is also possible to [override the rendering mode for a specific route](/solid-start/building-your-application/rendering-modes#per-route-configuration). + +## Type Signature -| Argument | Type | Default | Description | -| ------------ | ------------------------ | -------- | ----------------------------------------------------------------- | -| fn | fn: (context: PageEvent) | | A function that returns the static document for your application. | -| options.mode | string | "stream" | The SSR mode. Options are 'sync', 'async' and 'stream'. | +```tsx +type RenderingModes = "stream" | "async" | "sync"; + +function createHandler( + handler: () => (document: any, options?: any) => void, + options?: + | { mode?: RenderingModes } + | ((event: RequestEvent) => { mode: RenderingModes }) + | undefined +): (event: RequestEvent) => Response; +``` From 28afce15e04e6d9e8e51418f965ec92ba5fa62fe Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Mon, 20 Oct 2025 18:37:22 +0200 Subject: [PATCH 2/9] typo-1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../solid-start/building-your-application/rendering-modes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index 2a989e54d..3a85aeaa2 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -38,7 +38,7 @@ No suspense fallbacks are shown in the browser, which makes this mode ideal for Uses [`renderToStream`](/reference/rendering/render-to-stream) to render the page from Solid's core to render the page streaming. Leveraging [TransformableStream](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) to progressively send the HTML to the client-side. -This mode is ideal for performance and future-friendly apps. . +This mode is ideal for performance and future-friendly apps. ## Global Configuration From 2e8d4018c6f28a3d045153d834e1a442626c2566 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Mon, 20 Oct 2025 18:37:33 +0200 Subject: [PATCH 3/9] typo-2 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../solid-start/building-your-application/rendering-modes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index 3a85aeaa2..51111b35a 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -58,7 +58,7 @@ The value in [`entry-server.tsx`](/solid-start/reference/entrypoints/entry-serve import { createHandler, StartServer } from "@solidjs/start/server"; export default createHandler(() => ( - + ), { mode: "async" }); From 7a73d35f42bd28195a54d141e1a495129a2721d1 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Mon, 20 Oct 2025 18:37:42 +0200 Subject: [PATCH 4/9] typo-3 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../solid-start/building-your-application/rendering-modes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index 51111b35a..f9e674213 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -29,7 +29,7 @@ All async features are disabled and the page is rendered as soon as possible and ### Async Mode Uses [`renderToStringAsync`](/reference/rendering/render-to-string-async) to render the page from Solid's core to render the page asynchronously. -All Suspense boundares are resolved and rendered before being sent to the client-side. +All Suspense boundaries are resolved and rendered before being sent to the client-side. No suspense fallbacks are shown in the browser, which makes this mode ideal for SEO optimizations and bot support. From 926ff16760b0f89fc99388753aa2f8b023f69ed4 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Mon, 20 Oct 2025 18:37:56 +0200 Subject: [PATCH 5/9] typo-4 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../solid-start/building-your-application/rendering-modes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index f9e674213..8ca65422b 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -75,7 +75,7 @@ export default createHandler(() => ( ), { mode: (event) => { - return event.request.url.includes("/special-route") ? "async" : "stream"; + return { mode: event.request.url.includes("/special-route") ? "async" : "stream" }; } }); ``` From 08b8670cc84a73e1bf30b443ea7d7cb8aa2c77f6 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Mon, 20 Oct 2025 18:38:07 +0200 Subject: [PATCH 6/9] typooo Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../solid-start/building-your-application/rendering-modes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index 8ca65422b..ee5b45ff9 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -89,7 +89,7 @@ export default createHandler(() => ( ), { mode: (event) => { - return isBot(event.request.userAgent) ? "async" : "stream"; + return { mode: isBot(event.request.userAgent) ? "async" : "stream" }; } }); ``` From 717bca0d7a56972043cfedd5fe516c3e54ab1607 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Sun, 26 Oct 2025 19:40:47 +0100 Subject: [PATCH 7/9] big rewording --- .../rendering-modes.mdx | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index ee5b45ff9..48a658ccb 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -2,43 +2,58 @@ title: "Rendering Modes" --- -SolidStart has 3 kinds of rendering modes: `sync`, `async`, and `stream`. -Let's talk about how each of them work and which one to pick. +SolidStart has 3 kinds of rendering modes: -:::note -Default is **stream** and performance-wise should be preferred as a rule-of-thumb. -::: +- `sync`: renders on server with `renderToString` and performs Client-Side Rendering (CSR) for asynchronous features. +- `async`: renders on server with `renderToStringAsync`. Blocking the response until all asynchronous data fetching is resolved. +- `stream` (default): renders on server with `renderToStream`. Streaming the response as soon as possible and continuing to fetch asynchronous data in the background, resolving the page as soon as possible and sending next chunks. All modes have some degree of Server-Side Rendering, you may need to change them globally depending on your deployment provider. -And you may prefer to override them for better bot support and SEO. - -## Impacted Features - -| Feature | sync | async | stream | -| -------------------- | ----------- | --------------------------- | ----------------------- | -| Data fetching | Client-side | Server-side (blocking) | Server-side (streaming) | -| Suspense fallbacks | Yes | No | Yes | -| Time to first byte | Fast | Slower (waits for all data) | Faster | -| Total page load time | Slower | Fast (server fetches) | Faster (progressive) | ### Sync Mode Uses [`renderToString`](/reference/rendering/render-to-string) to render the page from Solid's core to render the page synchronously. All async features are disabled and the page is rendered as soon as possible and sent to the client-side where data fetching will happen post-hydration. +:::caution[Page Components] +In SolidStart, all page components are lazy-loaded by default. This means that `renderToString` will SSR only until `app.tsx` and the route components will be rendered client-side. +::: + +Asynchronous features will be directly impacted since rendering will mostly happen on the client-side. + +- Data-fetching: client-side only, first load will render Suspense fallbacks. +- Time To First Byte (TTFB): fast since the server-side rendering is minimal. +- Total page load time: slower since the client-side rendering is heavier. + ### Async Mode Uses [`renderToStringAsync`](/reference/rendering/render-to-string-async) to render the page from Solid's core to render the page asynchronously. All Suspense boundaries are resolved and rendered before being sent to the client-side. +:::tip[SEO and Bot Support] No suspense fallbacks are shown in the browser, which makes this mode ideal for SEO optimizations and bot support. +::: + +Asynchronous features will happen in the Server-Side during first render. + +- **Data-fetching**: first render will be similar to sync mode, but data fetching will still happen in the background and responses will be streamed in chunks as available. +- **Time To First Byte (TTFB)**: slower since the server-side rendering is heavier. +- **Total page load time**: faster than sync mode since the server-side tends to be faster than the client-side. -### Stream Mode +### Stream Mode (default) Uses [`renderToStream`](/reference/rendering/render-to-stream) to render the page from Solid's core to render the page streaming. Leveraging [TransformableStream](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) to progressively send the HTML to the client-side. -This mode is ideal for performance and future-friendly apps. +:::tip[Performance and Future-Friendly Apps] +This mode is ideal for performance and future-friendly apps. It provides best perceived performance and consumes less memory and CPU from the client-side. +::: + +Asynchronous features will happen in the Server-Side during first render. + +- **Data-fetching**: server-side only, data fetching will happen in the background and the page will be rendered as soon as possible. +- **Time To First Byte (TTFB)**: faster since the server-side rendering is lighter. +- **Total page load time**: faster since the server-side tends to be faster than the client-side. ## Global Configuration From c56434a341d41a546c7cb232879203e4fbb76562 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Sun, 26 Oct 2025 19:43:24 +0100 Subject: [PATCH 8/9] Update src/routes/solid-start/building-your-application/rendering-modes.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../solid-start/building-your-application/rendering-modes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index 48a658ccb..a62fe98ad 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -28,7 +28,7 @@ Asynchronous features will be directly impacted since rendering will mostly happ ### Async Mode Uses [`renderToStringAsync`](/reference/rendering/render-to-string-async) to render the page from Solid's core to render the page asynchronously. -All Suspense boundaries are resolved and rendered before being sent to the client-side. +Uses [`renderToStringAsync`](/reference/rendering/render-to-string-async) from Solid's core to render the page asynchronously. :::tip[SEO and Bot Support] No suspense fallbacks are shown in the browser, which makes this mode ideal for SEO optimizations and bot support. From ea97511cef75b012f6e64256ce92128a5b5033f5 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Sun, 26 Oct 2025 19:43:37 +0100 Subject: [PATCH 9/9] Update src/routes/solid-start/building-your-application/rendering-modes.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../solid-start/building-your-application/rendering-modes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/solid-start/building-your-application/rendering-modes.mdx b/src/routes/solid-start/building-your-application/rendering-modes.mdx index a62fe98ad..8ffa935b6 100644 --- a/src/routes/solid-start/building-your-application/rendering-modes.mdx +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -35,7 +35,7 @@ No suspense fallbacks are shown in the browser, which makes this mode ideal for ::: Asynchronous features will happen in the Server-Side during first render. - +Uses [`renderToStream`](/reference/rendering/render-to-stream) from Solid's core to render the page streaming. - **Data-fetching**: first render will be similar to sync mode, but data fetching will still happen in the background and responses will be streamed in chunks as available. - **Time To First Byte (TTFB)**: slower since the server-side rendering is heavier. - **Total page load time**: faster than sync mode since the server-side tends to be faster than the client-side.