Use with SSR

Static Extraction a.k.a. Server Side Rendering

Twind supports static extraction a.k.a. Server Side Rendering (SSR) out of the box.

Synchronous SSR

The following example assumes your app is using the tw named export from twind but the same logic can be applied to custom instances.

import { setup } from 'twind'
import { virtualSheet, getStyleTag } from 'twind/sheets'

const sheet = virtualSheet()

setup({ ...sharedOptions, sheet })

function ssr() {
  // 1. Reset the sheet for a new rendering
  sheet.reset()

  // 2. Render the app
  const body = renderTheApp()

  // 3. Create the style tag with all generated CSS rules
  const styleTag = getStyleTag(sheet)

  // 4. Generate the response html
  return `<!DOCTYPE html>
    <html lang="en">
      <head>${styleTag}</head>
      <body>${body}</body>
    </html>
  `
}

In order to prevent harmful code injection on the web, a Content Security Policy (CSP) may be put in place. During server-side rendering, a cryptographic nonce (number used once) may be embedded when generating a page on demand:

// ... other code is the same as before ...

// Usage with webpack: https://webpack.js.org/guides/csp/
const styleTag = getStyleTag(sheet, { nonce: __webpack_nonce__ })

Asynchronous SSR

❗ Please note the twind/server bundle is Node.JS only. ❗ This is an experimental feature and only supported for Node.JS >=12. care and please report any issue you find. Consider using the synchronous API when ever possible due to the relatively expensive nature of the promise introspection API provided by V8. Async server side rendering is implemented using async_hooks. Callback-based APIs and event emitters may not work or need special handling.

import { setup } from 'twind'
import { asyncVirtualSheet, getStyleTag } from 'twind/server'

const sheet = asyncVirtualSheet()

setup({ ...sharedOptions, sheet })

async function ssr() {
  // 1. Reset the sheet for a new rendering
  sheet.reset()

  // 2. Render the app
  const body = await renderTheApp()

  // 3. Create the style tag with all generated CSS rules
  const styleTag = getStyleTag(sheet)

  // 4. Generate the response html
  return `<!DOCTYPE html>
    <html lang="en">
      <head>${styleTag}</head>
      <body>${body}</body>
    </html>
  `
}

Streaming SSR

Supporting ReactDOM.renderToNodeStream and Vue.renderToStream is still on the roadmap...