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..8ffa935b6 --- /dev/null +++ b/src/routes/solid-start/building-your-application/rendering-modes.mdx @@ -0,0 +1,110 @@ +--- +title: "Rendering Modes" +--- + +SolidStart has 3 kinds of rendering modes: + +- `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. + +### 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. +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. +::: + +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. + +### 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. + +:::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 + +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 { mode: 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 { mode: 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; +```