Greg Bergé 4dffad7bd2 feat: welcome loadable
BREAKING CHANGE: API has completely changed, see documentation.
2018-10-29 13:04:07 +01:00

7.7 KiB

@loadable/server

Install

npm install @loadable/server

Modes

Loadable supports two modes, a static mode and a dynamic mode.

The static mode insert required chunks directly in the page whereas the dynamic mode loads them from your main bundle.

This table compares the two modes.

Mode @loadable/babel-plugin @loadable/webpack-plugin loadComponents() Perf
Static Required Required Not required ++
Dynamic Required No required Required +

1. Install @loadable/babel-plugin

.babelrc

{
  "plugins": ["@loadable/babel-plugin"]
}

2. Install @loadable/webpack-plugin

webpack.config.js

const LoadablePlugin = require('@loadable/webpack-plugin')

module.exports = {
  /* Your webpack config... */
  plugins: [new HtmlWebpackPlugin()],
}

3. Setup LoadableState server-side (with manifest)

import path from 'path'
import { LoadableState } from '@loadable/server'
// This is the manifest generated by webpack
import manifest from '../dist/loadable-manifest.json'

const loadableState = new LoadableState(manifest)

const html = renderToString(
  <LoadableStateManager state={loadableState}>
    <YourApp />
  </LoadableStateManager>,
)

const scriptTags = loadableState.getScriptTags() // or loadableState.getScriptElements();

Dynamic mode

1. Install @loadable/babel-plugin

.babelrc

{
  "plugins": ["@loadable/babel-plugin"]
}

2. Setup LoadableState server-side (without manifest)

import path from 'path'
import { LoadableState } from '@loadable/server'

const loadableState = new LoadableState()

const html = renderToString(
  <LoadableStateManager state={loadableState}>
    <YourApp />
  </LoadableStateManager>,
)

const scriptTags = loadableState.getScriptTags() // or loadableState.getScriptElements();

3. Use loadComponents() client-side

import { hydrate } from 'react-dom'
import { loadComponents } from '@loadable/component'

// Call `loadComponents()` before rendering your application
loadComponents().then(() => {
  hydrate(<YourApp />, root)
})

Collecting chunks

The basic API goes as follows:

import { renderToString } from 'react-dom/server'
import { LoadableState } from '@loadable/server'

const loadableState = new LoadableState()
// or new LoadableState(manifest), see modes documentation
const html = renderToString(loadableState.collectChunks(<YourApp />))
const scriptTags = loadableState.getScriptTags() // or loadableState.getScriptElements();

The collectChunks method wraps your element in a provider. Optionally you can use the LoadableStateManager provider directly, instead of this method. Just make sure not to use it on the client-side.

import { renderToString } from 'react-dom/server'
import { LoadableState, LoadableStateManager } from 'styled-components'

const loadableState = new LoadableState()
const html = renderToString(
  <LoadableStateManager state={loadableState}>
    <YourApp />
  </LoadableStateManager>,
)

const scriptTags = loadableState.getScriptTags() // or loadableState.getScriptElements();

The loadableState.getScriptTags() returns a string of multiple <script> tags. You must include them before your main bundle.

Alternatively the LoadableState also has a getScriptElements() method that returns an array of React elements.

loadableState.getScriptTags() and loadableState.getScriptElements() can only be called after your element is rendered. As a result, components from loadableState.getScriptElements() cannot be combined with <YourApp /> into a larger component.

Streaming rendering

Loadable is compatible with streaming rendering, if you use it you have to include script when the stream is complete.

import { renderToNodeStream } from 'react-dom/server'
import { LoadableState } from '@loadable/server'

// if you're using express.js, you'd have access to the response object "res"

// typically you'd want to write some preliminary HTML, since React doesn't handle this
res.write('<html><head><title>Test</title></head><body>')

const loadableState = new LoadableState()
// or new LoadableState(manifest), see modes documentation
const jsx = loadableState.collectChunks(<YourApp />)
const stream = renderToNodeStream(jsx)

// you'd then pipe the stream into the response object until it's done
stream.pipe(
  res,
  { end: false },
)

// and finalize the response with closing HTML
stream.on('end', () =>
  res.end(`${loadableState.getScriptTags()}</body></html>`),
)

Streaming rendering is not compatible with prefetch <link> tags.

Prefetching

To improve performance, you can include <link ref="preload"> in the head of your HTML page. If you use Prefetch feature of @loadable/component, you can insert them server-side.

import path from 'path'
import { LoadableState } from '@loadable/server'
// This is the manifest generated by webpack
import manifest from '../dist/loadable-manifest.json'

const loadableState = new LoadableState(manifest)

const html = renderToString(
  <LoadableStateManager state={loadableState}>
    <YourApp />
  </LoadableStateManager>,
)

const prefetchTags = loadableState.getPrefetchTags() // or loadableState.getPrefetchElements();

const html = `<html>
  <head>${prefetchTags}</head>
  <body>
    <div id="root">${html}</div>
  </body>
</html>`

It only works with renderToString API. Since <link> must be added in the <head>, you can't do it using renderToNodeStream.

API

LoadableState

Used to collect chunks server-side and get them as script tags or script elements.

Arguments Description
manifest Optional manifest file path generated using @loadable/webpack-plugin.
import { LoadableState } from '@loadable/server'

const loadableState = new LoadableState()

// or using manifest
const loadableState = new LoadableState(manifest)

loadableState.collectChunks

Wrap your application in a LoadableManager.

Arguments Description
element JSX element that will be wrapped in LoadableManager.
const app = loadableState.collectChunks(<YourApp />)

loadableState.getScriptTags

Get scripts as a string of <script> tags.

const body = `<body><div id="root">${html}</div>${loadableState.getScriptTags()}</body>`

loadableState.getScriptElements

Get scripts as an array of React <script> elements.

const body = renderToString(
  <body>
    <div id="root" dangerouslySetInnerHtml={{ __html: html }} />
    {loadableState.getScriptElements()}
  </body>,
)

loadableState.getPrefetchTags

Get prefetch links as a string of <link> tags.

const head = `<head>${loadableState.getPrefetchTags()}</head>`

loadableState.getPrefetchElements

Get prefetch links as an array of React <link> elements.

const head = renderToString(<head>{loadableState.getPrefetchElements()}</head>)

LoadableManager

Used to inject a LoadableState in the context of your application.

import { LoadableState, LoadableManager } from '@loadable/server'

const loadableState = new LoadableState()

const app = (
  <LoadableManager state={loadableState}>
    <YourApp />
  </LoadableManager>
)

License

MIT