前記事のGatsby 製サイトに Algolia のサイト内検索を実装するを実現するにあたって、色々ライブラリが増えるけどページのロード時間は増やしたくなかったので React Suspense(以下 Suspense)+ React.lazy + Dynamic import で Code splitting を試みたところハマったので備忘録を残します。
動かないので GitHub にはコミットされていませんが、こんな感じのことをすると Gatsby のビルドがこける。
import React, { Suspense, lazy } from 'react'
export function Hoge() {
const SomeComponent = lazy(() => import('./SomeComponent'))
return (
<Suspense fallback={null}>
<SomeComponent />
</Suspense>
)
}
このコードはgatsby develop
で動作確認しているときは普通に動くので余計にハマった。
gatsby build
すると以下のエラーが発生した。
https://reactjs.org/docs/error-decoder.html/?invariant=294
これでは分からないのでデコードしてみると、以下のエラーだった。
ReactDOMServer does not yet support Suspense.
まだサポートされていなかった。
もしかして使ってる React のバージョンが古いんじゃないかと思ったものの、バージョンは記事執筆時の最新(16.8.6)だった
いつ頃使えるようになるのか調べてみたが、明確にどのバージョンでリリースされるかは明記されていなかった。
Suspense for Server Rendering
We started designing a new server renderer that supports Suspense (including waiting for asynchronous data on the server without double rendering) and progressively loading and hydrating page content in chunks for best user experience. You can watch an overview of its early prototype in this talk. The new server renderer is going to be our major focus in 2019, but it’s too early to say anything about its release schedule. Its development, as always, will happen on GitHub.
Gatsby にすでに Issue が報告されていた。
— Suspense and React.lazy isn’t working · Issue #11960 · gatsbyjs/gatsby
回答によると、まだ Suspense+React.lazy はサポートされていないので、サポートされるまでLoadable components
というパッケージを使ってねとのこと。
Gatsby is using SSR which Suspense & React.Lazy not yet support. You can move to a full client site to use those features but to have the static generation of pages you sadly can’t. React recommonds to use the Loadable components package until SSR is resolved.
— Suspense and React.lazy isn’t working · Issue #11960 · gatsbyjs/gatsby
React.lazy の公式ドキュメントにでかでかと書いてあった。
Loadable Components と書かれているリンク先がこのリポジトリ。
smooth-code/loadable-components
使い方は Suspense + React.lazy を一手に担う感じ。大きくコードは変わらない。
import React from 'react'
import loadable from '@loadable/component'
const OtherComponent = loadable(() => import('./OtherComponent'))
function MyComponent() {
return <OtherComponent />
}
このコードを Suspense + React.lazy で書くとこうなる。
ほぼ Suspense+React.lazy と同様の使用感で使える。
import React, { Suspense, lazy } from 'react'
const OtherComponent = lazy(() => import('./OtherComponent'))
function MyComponent() {
return (
<Suspense fallback={null}>
<OtherComponent />
</Suspense>
)
}
結果的にコミットされた dynamic import はこうなった。