Something went wrong! {error.message}
; } ``` ## Controlling When to Wait for Full HTML Streaming improves perceived speed, but in some cases (SEO crawlers, A/B buckets, compliance pages) you may want to wait for all content before sending the response. Modern.js decides the streaming mode with this priority: 1. Request header `x-should-stream-all` (set per-request in middleware). 2. Env `MODERN_JS_STREAM_TO_STRING` (forces full HTML). 3. [isbot](https://www.npmjs.com/package/isbot) check on `user-agent` (bots get full HTML). 4. Default: stream shell first. Set the header in your middleware to choose the behavior dynamically: ```ts title="middleware example" export const middleware = async (ctx, next) => { const ua = ctx.req.header('user-agent') || ''; const shouldWaitAll = /Lighthouse|Googlebot/i.test(ua) || ctx.req.path === '/marketing'; // Write a boolean string: true -> onAllReady, false -> onShellReady ctx.req.headers.set('x-should-stream-all', String(shouldWaitAll)); await next(); }; ``` ## Related Documentation - [Rendering Mode Overview](/guides/basic-features/render/overview.md) - [Server-Side Rendering (SSR)](/guides/basic-features/render/ssr.md) - [Rendering Cache](/guides/basic-features/render/ssr-cache.md) - [React Server Components (RSC)](/guides/basic-features/render/rsc.md) - Use with Streaming SSR - [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37) - React 18 Architecture Overview --- url: /guides/basic-features/render/ssr-cache.md --- # Rendering Cache When developing applications, sometimes we cache computation results using hooks like React's `useMemo` and `useCallback`. By leveraging caching, we can reduce the number of computations, thus saving CPU resources and improving user experience. Modern.js supports caching server-side rendering (SSR) results, reducing the computational and rendering time during subsequent requests. This accelerates page load time and improves user experience. Additionally, caching lowers server load, conserves computational resources, and speeds up user access. ## Configuration Create a `server/cache.[t|j]s` file in your application and export the `cacheOption` configuration to enable SSR rendering cache: ```ts title="server/cache.ts" import type { CacheOption } from '@modern-js/server-runtime'; export const cacheOption: CacheOption = { maxAge: 500, // ms staleWhileRevalidate: 1000, // ms }; ``` ## Configuration Details ### Cache Configuration The caching strategy implements [stale-while-revalidate](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control). Within the `maxAge` period, the cache content is directly returned. Exceeding `maxAge` but within `staleWhileRevalidate`, the cache content is still returned directly, but it re-renders asynchronously. **Object Type** ```ts export interface CacheControl { maxAge: number; staleWhileRevalidate: number; customKey?: string | ((pathname: string) => string); } ``` Here, `customKey` is the custom cache key. By default, Modern.js uses the request `pathname` as the cache key, but developers can define it when necessary. **Function Type** ```ts export type CacheOptionProvider = ( req: IncomingMessage, ) => PromiseClick me!
This part is static.
{/* Client Component can be seamlessly embedded in Server Component */}{text}
; }; ``` Now run the `dev` command to start the project, and access `http://localhost:8080/` to find that the request for `/api/hello` has been intercepted:  Finally, modify the frontend code `src/routes/page.tsx`, and call the login interface before accessing `/api/hello`: :::note This part does not implement a real login interface; the code is just for demonstration. ::: ```ts import { useState, useEffect } from 'react'; import { get as hello } from '@api/hello'; import { post as login } from '@api/login'; export default () => { const [text, setText] = useState(''); useEffect(() => { async function fetchAfterLogin() { const { code } = await login(); if (code === 0) { const { message } = await hello(); setText(message); } } fetchAfterLogin(); }, []); return{text}
; }; ``` Refresh the page, and you can see that the access to `/api/hello` is successful:  The above code simulates defining middleware in `server/Modern.server.ts` and implements a simple login function. Similarly, other functionalities can be implemented in this configuration file to extend the BFF Server. --- url: /guides/advanced-features/bff/sdk.md --- # Extend Request SDK The unified invocation of BFF functions is isomorphic in both CSR and SSR. The request SDK encapsulated by Modern.js relies on the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) on the browser side, and on [node-fetch](https://www.npmjs.com/package/node-fetch) on the server side. However, in actual business scenarios, additional processing may be required for requests or responses, such as: - Writing authentication information in the request headers - Uniform handling of response data or errors - Using other methods to send requests when the native fetch function is unavailable on specific platforms To address these scenarios, Modern.js provides the `configure` function, which offers a series of extension capabilities. You can use it to configure SSR passthrough request headers, add interceptors, or customize the request SDK. :::caution Note The `configure` function needs to be called before all BFF requests are sent to ensure that the default request configuration is overridden. ::: ```tsx title="routes/page.tsx" import { configure } from '@modern-js/plugin-bff/client'; configure({ // ... }); const Index = () =>Current language: {language}
{supportedLanguages.map(lang => ( ))}{t('welcome')}
{supportedLanguages.map(lang => ( ))}{info?.error.message}
{t('about')}
{t('about')}
; }; export default () => { return ({info?.error?.message}
Hello Modern.js!