{
    "componentChunkName": "component---src-templates-blog-post-jsx",
    "path": "/post/dynamic-import-tips-for-gatsby/",
    "result": {"data":{"site":{"siteMetadata":{"title":"WEB EGG","author":"Leko - CTO at Yuimedi"}},"markdownRemark":{"id":"7abcf071-be73-5e79-8f69-06b345c43c5e","excerpt":"前記事のGatsby 製サイトに Algolia のサイト内検索を実装するを実現するにあたって、色々ライブラリが増えるけどページのロード時間は増やしたくなかったので React Suspense（以下 Suspense）＋ React.lazy ＋ Dynamic import で Code splitting…","html":"<p>前記事の<a href=\"/post/on-site-search-in-gatsby-with-algolia/\">Gatsby 製サイトに Algolia のサイト内検索を実装する</a>を実現するにあたって、色々ライブラリが増えるけどページのロード時間は増やしたくなかったので React Suspense（以下 Suspense）＋ React.lazy ＋ Dynamic import で Code splitting を試みたところハマったので備忘録を残します。</p>\n<!--more-->\n<h2 id=\"tldr\" style=\"position:relative;\"><a href=\"#tldr\" aria-label=\"tldr permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>TL;DR</h2>\n<ul>\n<li>まだ React Suspense は Gatsby（SSR）で使用できない</li>\n<li>SSR での Suspense サポートは React 16.x のロードマップに含まれている</li>\n<li>SSR での Suspense をサポートするまでは<a href=\"https://github.com/smooth-code/loadable-components\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">@loadable/component</a>を使ってねと Gaysby の Issue も React の公式ドキュメントも言っている</li>\n</ul>\n<h2 id=\"再現コード\" style=\"position:relative;\"><a href=\"#%E5%86%8D%E7%8F%BE%E3%82%B3%E3%83%BC%E3%83%89\" aria-label=\"再現コード permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>再現コード</h2>\n<p>動かないので GitHub にはコミットされていませんが、こんな感じのことをすると Gatsby のビルドがこける。</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> Suspense<span class=\"token punctuation\">,</span> lazy <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">Hoge</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> SomeComponent <span class=\"token operator\">=</span> <span class=\"token function\">lazy</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./SomeComponent'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">SomeComponent</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>このコードは<code>gatsby develop</code>で動作確認しているときは普通に動くので余計にハマった。</p>\n<h2 id=\"エラーの内容\" style=\"position:relative;\"><a href=\"#%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E5%86%85%E5%AE%B9\" aria-label=\"エラーの内容 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>エラーの内容</h2>\n<p><code>gatsby build</code>すると以下のエラーが発生した。</p>\n<p><a href=\"https://reactjs.org/docs/error-decoder.html/?invariant=294\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://reactjs.org/docs/error-decoder.html/?invariant=294</a></p>\n<p>これでは分からないのでデコードしてみると、以下のエラーだった。</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ReactDOMServer does not yet support Suspense.</code></pre></div>\n<p>まだサポートされていなかった。<br>\nもしかして使ってる React のバージョンが古いんじゃないかと思ったものの、バージョンは記事執筆時の最新（16.8.6）だった</p>\n<h2 id=\"react-のロードマップを調べる\" style=\"position:relative;\"><a href=\"#react-%E3%81%AE%E3%83%AD%E3%83%BC%E3%83%89%E3%83%9E%E3%83%83%E3%83%97%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B\" aria-label=\"react のロードマップを調べる permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React のロードマップを調べる</h2>\n<p>いつ頃使えるようになるのか調べてみたが、明確にどのバージョンでリリースされるかは明記されていなかった。</p>\n<blockquote>\n<p><strong>Suspense for Server Rendering</strong><br>\nWe 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.</p>\n<p>— <a href=\"https://reactjs.org/blog/2018/11/27/react-16-roadmap.html#suspense-for-server-rendering\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">React 16.x Roadmap – React Blog</a></p>\n</blockquote>\n<h2 id=\"gatsby-の-issue\" style=\"position:relative;\"><a href=\"#gatsby-%E3%81%AE-issue\" aria-label=\"gatsby の issue permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gatsby の Issue</h2>\n<p>Gatsby にすでに Issue が報告されていた。</p>\n<blockquote>\n<p>— <a href=\"https://github.com/gatsbyjs/gatsby/issues/11960\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Suspense and React.lazy isn’t working · Issue #11960 · gatsbyjs/gatsby</a></p>\n</blockquote>\n<p>回答によると、まだ Suspense+React.lazy はサポートされていないので、サポートされるまで<code>Loadable components</code>というパッケージを使ってねとのこと。</p>\n<blockquote>\n<p>Gatsby is using SSR which Suspense &#x26; 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.</p>\n<p>— <a href=\"https://github.com/gatsbyjs/gatsby/issues/11960\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Suspense and React.lazy isn’t working · Issue #11960 · gatsbyjs/gatsby</a></p>\n</blockquote>\n<h2 id=\"work-around\" style=\"position:relative;\"><a href=\"#work-around\" aria-label=\"work around permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>work around</h2>\n<p>React.lazy の公式ドキュメントにでかでかと書いてあった。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 668px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/18f351fb20245875f6703c21287fcda3/c211c/caution.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 31.137724550898206%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'125\\'%20viewBox=\\'0%200%20400%20125\\'%20preserveAspectRatio=\\'none\\'%3e%3cpath%20d=\\'M158%2054c-1%202-2%202-2%201h-6c-3%200-4%201-4%202-1%202%202%203%203%201h3l1-1c0%202%2020%202%2020%200%201-1-1-3-3-2l-1-1h-1c0%202%200%202-2%201l-2-1c0%202-3%202-4%200h-2m78%200l-7%201c-5%200-6%200-6%202s2%203%202%200h1c0%202%205%202%205%200h1c1%202%2011%202%2011%200h1l2%202%201-2h1l1%202%201%201c1%202%203%200%203-3%200-2%200-2-4-2-3%201-4%200-4-1h-1c-1%202-7%202-7%200h-1M48%2067h-2c-1%200-2%200-2%202h-1c0-3-3-2-2%201l1%201%202%201%207-3%201%201%201%202v-2c0-2%200-2%201%200s5%202%205%200l1-1%201%201v1l2%201c1%202%203%200%203-3%200-2%200-2-2-2h-7l-1%201c-2-2-8-2-8-1m67%200h-7c-5%200-5%200-5%202s0%202%201%201l1-1c0%203%202%204%203%202h1l1-1h2l8%201h1l1-1c0-1%201-1%202%201h3c2%202%204%200%204-3%200-1%200-2-1-1h-15m81%200h-11c-9%200-11%200-13%202h-1c1-2%200-2-5-2s-7%201-7%202l1%202%201-2%201%201c1%202%203%203%203%201h9l1-2%201%201%201%202v-2l1-1c0%202%203%203%203%201h4c0%201%203%202%204%201h1l1-1h2c3%202%204%202%205%201%201-3%200-5-2-4m36%201c-1%202%201%204%205%203l5-1h2c0-2%201-2%201-1%200%202%203%204%204%202h4l2-1%201-1h1c0%202%204%203%205%202h1l1-2%201%201c1%201%201%201%201-1s0-2-15-2c-10%200-14%201-15%202h-3l1-2v-1l-2%202\\'%20fill=\\'%23d3d3d3\\'%20fill-rule=\\'evenodd\\'/%3e%3c/svg%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n          <source\n              srcset=\"/static/18f351fb20245875f6703c21287fcda3/5251b/caution.webp 167w,\n/static/18f351fb20245875f6703c21287fcda3/7390e/caution.webp 334w,\n/static/18f351fb20245875f6703c21287fcda3/7c056/caution.webp 668w,\n/static/18f351fb20245875f6703c21287fcda3/0a92e/caution.webp 1002w,\n/static/18f351fb20245875f6703c21287fcda3/7fa3c/caution.webp 1336w,\n/static/18f351fb20245875f6703c21287fcda3/dfb61/caution.webp 1502w\"\n              sizes=\"(max-width: 668px) 100vw, 668px\"\n              type=\"image/webp\"\n            />\n          <source\n            srcset=\"/static/18f351fb20245875f6703c21287fcda3/21521/caution.png 167w,\n/static/18f351fb20245875f6703c21287fcda3/86d36/caution.png 334w,\n/static/18f351fb20245875f6703c21287fcda3/74866/caution.png 668w,\n/static/18f351fb20245875f6703c21287fcda3/d69c4/caution.png 1002w,\n/static/18f351fb20245875f6703c21287fcda3/9685e/caution.png 1336w,\n/static/18f351fb20245875f6703c21287fcda3/c211c/caution.png 1502w\"\n            sizes=\"(max-width: 668px) 100vw, 668px\"\n            type=\"image/png\"\n          />\n          <img\n            class=\"gatsby-resp-image-image\"\n            src=\"/static/18f351fb20245875f6703c21287fcda3/74866/caution.png\"\n            alt=\"caution\"\n            title=\"caution\"\n            loading=\"lazy\"\n            decoding=\"async\"\n            style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n          />\n        </picture>\n  </a>\n    </span></p>\n<p>Loadable Components と書かれているリンク先がこのリポジトリ。</p>\n<p><a href=\"https://github.com/smooth-code/loadable-components\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">smooth-code/loadable-components</a></p>\n<p>使い方は Suspense + React.lazy を一手に担う感じ。大きくコードは変わらない。</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> loadable <span class=\"token keyword\">from</span> <span class=\"token string\">'@loadable/component'</span>\n\n<span class=\"token keyword\">const</span> OtherComponent <span class=\"token operator\">=</span> <span class=\"token function\">loadable</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./OtherComponent'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">MyComponent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">OtherComponent</span></span> <span class=\"token punctuation\">/></span></span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>このコードを Suspense + React.lazy で書くとこうなる。<br>\nほぼ Suspense+React.lazy と同様の使用感で使える。</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> Suspense<span class=\"token punctuation\">,</span> lazy <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n\n<span class=\"token keyword\">const</span> OtherComponent <span class=\"token operator\">=</span> <span class=\"token function\">lazy</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./OtherComponent'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">MyComponent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">OtherComponent</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>結果的にコミットされた dynamic import は<a href=\"https://github.com/Leko/WEB-EGG/blob/6e088d55d43ea8988282044a67e39fb573bd12a4/src/components/Layout.js#L14-L29\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こう</a>なった。</p>","timeToRead":4,"frontmatter":{"title":"GatsbyでReactコンポーネントをDynamic importしてCode Splitするwork around","tags":["JavaScript","Gatsby","React"],"date":"May 07, 2019","featuredImage":null}}},"pageContext":{"slug":"/dynamic-import-tips-for-gatsby/","previous":{"fields":{"slug":"/on-site-search-in-gatsby-with-algolia/"},"frontmatter":{"title":"Gatsby製サイトにAlgoliaのサイト内検索を実装する","tags":["Algolia","JavaScript","Node.js","Gatsby","React"]}},"next":{"fields":{"slug":"/convert-any-html-element-to-image/"},"frontmatter":{"title":"シンタックスハイライト済みのソースコードの画像をブラウザだけで作成したい","tags":["JavaScript","Canvas"]}}}},
    "staticQueryHashes": ["2585454260","2954598359"]}