import Layout from 'lib/components/layout'

export const meta = {
  title: '服务端渲染',
  group: '快速上手',
  index: 15,
}

## 服务端渲染

**所有的 Geist UI 组件**都能完美适应服务端渲染，实际上，你现在所见的文档站点就是来自服务端渲染。

一个常见的 React 组件在服务端被渲染为 HTML 字符串通常包含两部分：HTML 骨架与样式，
它们共同构成了请求中返回的首个字符串，这能有效的保证用户尽可能早的阅读到页面内容 (而不需要等待额外地 JavaScript 资源加载与解析)。

在 Geist 中，你要做的只是把 Geist 生成的样式文本信息添加到服务端渲染工具中，无论 Next.js 还是自行构建的 HTTP 服务器。

### 使用 Next.js

在 `next.js` 框架中，你首先需要创建 `_document.js` 文件来填充自定义信息，
请参考 [Next.js](https://nextjs.org/docs/advanced-features/custom-document) 的官方文档了解此文件的影响和意义。

随后我们将以下示例代码加入到文件中：

```js
// NAME:pages/_document.js
import { Fragment } from "react"
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { CssBaseline } from '@geist-ui/core'

class MyDocument extends Document {
  static async getInitialProps (ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    const styles = CssBaseline.flush()

    return {
      ...initialProps,
      styles: [
        <Fragment key="1">
          {initialProps.styles}
          {styles}
        </Fragment>,
      ],
    }
  }

  render() { ... }
}
```

示例中的 `flush` 方法用于收集 Geist 在当前页面中产生的样式，每个项目只需要设置一次。这里也准备了一个完整的 [应用示例](https://github.com/unix/unix.bio/blob/template/pages/_document.tsx) 供作参考。

### 定制服务端

在你自定义的服务端或其他预渲染框架中，你可以通过函数 `CssBaseline.flush` 获取所有样式文本。

```js
import React from 'react'
import ReactDOM from 'react-dom/server'
import { CssBaseline } from 'geist-ui/core'
import App from './app'

export default (req, res) => {
  const app = ReactDOM.renderToString(<App />)
  const styles = CssBaseline.flush()
  const html = ReactDOM.renderToStaticMarkup(
    <html>
      <head>{styles}</head>
      <body>
        <div id="root" dangerouslySetInnerHTML={{ __html: app }} />
      </body>
    </html>,
  )
  res.end('<!doctype html>' + html)
}
```

export default ({ children }) => <Layout meta={meta}>{children}</Layout>
