reset
import React, { Fragment, Suspense } from 'react'
import Head from '@ninetails-monorepo-react-ssr/react-kabocha'
import { Link, Route, Switch } from 'react-router-dom'
const UniversalSuspense = global.window ? Suspense : Fragment
const test = {
  read (timeout, cache = global.window) {
    if (this.value) {
      if (cache) {
        return this.value
      }
      const output = this.value
      delete this.value
      delete this.promise
      return output
    }
    if (this.promise) {
      throw this.promise
    }
    this.promise = new Promise(resolve => {
      console.log('settimeout start', Date.now() / 1000)
      setTimeout(() => {
        console.log('settimeout end', Date.now() / 1000)
        this.value = 'foo'
        resolve(this.value)
      }, timeout)
    })
    throw this.promise
  }
}
function LazyTest () {
  const testValue = test.read(2000)
  return <div>{testValue}</div>
}
function Home () {
  return (
    <div>
      <Head>
        <title>Home</title>
      </Head>
      Home
    </div>
  )
}
function About () {
  return (
    <div>
      <Head>
        <title>About</title>
      </Head>
      About
      <UniversalSuspense maxDuration={500} fallback={<div>loading...</div>}>
        <LazyTest />
      </UniversalSuspense>
    </div>
  )
}
const App = () => (
  <div>
    <Head>
      <meta charSet='utf-8' />
      <meta name='viewport' content='width=device-width, initial-scale=1' />
    </Head>
    <nav>
      <ul>
        <li>
          <Link to='/'>Home</Link>
        </li>
        <li>
          <Link to='/about'>About</Link>
        </li>
      </ul>
    </nav>
    <Switch>
      <Route exact path='/' component={Home} />
      <Route path='/about' component={About} />
    </Switch>
  </div>
)
export default Appimport React from 'react'
import ReactDOM from 'react-dom'
import { HeadProvider } from '@ninetails-monorepo-react-ssr/react-kabocha'
import { BrowserRouter as Router } from 'react-router-dom'
import getRoot from './client/getRoot'
import App from './App'
const root = getRoot(process.env.REACT_APP_ROOT)
ReactDOM.createRoot(root, { hydrate: root.hasChildNodes() }).render(
  <HeadProvider>
    <Router>
      <App />
    </Router>
  </HeadProvider>
)import React from 'react'
import { renderToStaticNodeStream, renderToString } from 'react-dom/server'
import {
  HeadProvider,
  createRegistry
} from '@ninetails-monorepo-react-ssr/react-kabocha'
import { StaticRouter as Router } from 'react-router-dom'
import App from './App'
async function renderContent (props) {
  try {
    return renderToString(
      <HeadProvider registry={props.registry}>
        <Router location={props.location} context={props.context}>
          <App />
        </Router>
      </HeadProvider>
    )
  } catch (err) {
    if (err instanceof Promise) {
      await err
      return renderContent(props)
    }
    throw err
  }
}
function serverRenderer ({ clientStats, serverStats }) {
  const { main } = clientStats.assetsByChunkName
  const mainSrc = typeof main === 'string' ? main : main[0]
  return async (req, res, next) => {
    const registry = createRegistry()
    const context = {}
    try {
      const content = await renderContent({
        context,
        location: req.url,
        registry
      })
      if (context.url) {
        return res.redirect(301, context.url)
      }
      res.status(200).write('<!doctype html>')
      renderToStaticNodeStream(
        <html>
          <head>{registry.head()}</head>
          <body>
            <div
              id={process.env.REACT_APP_ROOT || 'root'}
              dangerouslySetInnerHTML={{ __html: content }}
            />
            <script src={`/${mainSrc}`} />
          </body>
        </html>
      ).pipe(
        res,
        { end: 'false' }
      )
    } catch (err) {
      // @todo error page
      console.error(err)
      res.status(500).send('Server error')
    }
  }
}
export default serverRenderer