[{"data":1,"prerenderedAt":263},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-bundle-splitting-with-react-s-lazy-and-suspense-i18n-slugs":134,"language-blog-slug-en-bundle-splitting-with-react-s-lazy-and-suspense":138},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135],{"locale":136,"value":137},"en","bundle-splitting-with-react-s-lazy-and-suspense",{"page":139},{"slug":137,"i18nSlugs":140,"social":142,"title":143,"subtitle":79,"isArchived":147,"headerIllustration":148,"date":149,"authors":150,"introTitle":144,"items":159,"pivots":260,"relatedBlogPosts":261,"tags":262,"onMountedScript":163,"onUnmountedScript":163},[141],{"locale":136,"value":137},{"title":143,"description":144,"image":145},"Bundle splitting with React’s lazy & Suspense","A guide to using React suspense and lazy loading components",{"url":146},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1618221749-react-lazy-loading-cover.png",false,null,"2021-03-30T02:00:00.000+02:00",[151],{"name":152,"lastName":153,"slug":154,"image":155},"Sjoerd","Beentjes","sjoerd",{"url":156,"alt":148,"width":157,"height":158},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534892-sjoerd.jpg",1637,2182,[160,165,169,174,177,186,189,192,195,198,205,210,214,217,220,223,229,233,236,239,243,246,249,256],{"__typename":161,"id":162,"title":163,"body":164},"TextSectionRecord","25270408","","\u003Cp>\u003Cspan class=\" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\">When creating an application using a framework like React, bundle sizes are important. They can grow fast, especially when using a lot of external packages. Most of the the time the application doesn&rsquo;t need all these packages \u003C\u002Fspan>\u003Cspan class=\" author-d-4z65zz66zl57z75zyiz66zfr2fz87zwz89znuj6z89zdz88zz68zdtz84zz78zuz65z9ynz76zz67zz70z0z71z1z90zz70zdz76zeasz67zg\">up front\u003C\u002Fspan>\u003Cspan class=\" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\">, but only when they&rsquo;re used in the application. To achieve this we can use bundle splitting provided by React using \u003Ccode>React.lazy()\u003C\u002Fcode>.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":161,"id":166,"title":167,"body":168},"25270409"," Analyse your bundle & identify large components","\u003Cp class=\"p1\">\u003Cspan class=\"s1\">We know that the bundle size is large, but how do we know which components to blame? \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fwebpack-bundle-analyzer\">\u003Cspan class=\"s2\">webpack-bundle-analyzer\u003C\u002Fspan>\u003C\u002Fa> is the perfect tool to investigate that. When using \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fcreate-react-app\">\u003Cspan class=\"s2\">create-react-app\u003C\u002Fspan>\u003C\u002Fa>, you can add this scripts to your package.json:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":171,"language":172,"body":173},"CodeBlockRecord","25270410","js","\u002F\u002F generate build including bundle-stats.json\nnpm run build -- --stats\n\n\u002F\u002F analyse bundle-stats.json\nwebpack-bundle-analyzer .\u002Fbuild\u002Fbundle-stats.json ",{"__typename":161,"id":175,"title":163,"body":176},"25273066","\u003Cp>\u003Cspan class=\" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\">The analyser produces an interactive web page that looks like this:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":179,"image":180,"caption":182,"fullWidth":147,"captionPosition":185},"ImageRecord","25270525",{"url":181,"alt":182,"width":183,"height":184},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1616161740-ume2qp5v.png","Analysis of the bundle without any bundle splitting",1600,853,"bottom",{"__typename":161,"id":187,"title":163,"body":188},"25270526","\u003Cp class=\"p1\">\u003Cspan class=\"s1\">We see that some packages take up a lot of space. They will get loaded and parsed before the application mounts in the DOM, but it&rsquo;s possible they&rsquo;re not needed on the page we visit. It would be nice to separate them into their own bundle, and load them only when needed.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp class=\"p1\">\u003Cspan class=\"s1\">Code splitting in React can be achieved by something called &lsquo;dynamic imports&rsquo; and \u003Ccode>React.lazy\u003C\u002Fcode>, which looks something like this:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":190,"language":172,"body":191},"25270545","import * as React from 'react'\nimport Users from '.\u002FUsers'\n\nconst Posts = React.lazy(() => import('.\u002FPosts'))\n\n\u002F\u002F rest of component file",{"__typename":161,"id":193,"title":163,"body":194},"25270546","\u003Cp>\u003Cspan class=\"thread-296788118386388161690778 author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\">This automatically results in a separate bundle for the \u003C\u002Fspan>\u003Cspan class=\"thread-740402778046715133105797 author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\">Posts\u003C\u002Fspan>\u003Cspan class=\"thread-296788118386388161690778 thread-593773691092964800085027 author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\"> component\u003C\u002Fspan>\u003Cspan class=\"thread-296788118386388161690778 author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\">, which then gets loaded asynchronously when it is used in the application.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":161,"id":196,"title":163,"body":197},"25270556","\u003Cp>Below you see the result of bundle splitting in the bundle shown earlier in this post (screenshots from the \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002Fcomponentizer\" rel=\"noreferrer nofollow noopener\">componentizer\u003C\u002Fa> app):\u003C\u002Fp>",{"__typename":178,"id":199,"image":200,"caption":202,"fullWidth":147,"captionPosition":185},"25270557",{"url":201,"alt":202,"width":203,"height":204},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1616162592-6gxj-fw2.png","Route-level bundle splitting",1280,682,{"__typename":178,"id":206,"image":207,"caption":209,"fullWidth":147,"captionPosition":185},"25270558",{"url":208,"alt":209,"width":203,"height":204},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1616162613-x-liegam.png","Route & component level bundle splitting",{"__typename":161,"id":211,"title":212,"body":213},"25270656","How does this work?","\u003Cp class=\"p1\">\u003Cspan class=\"s1\">To be clear about what happens when using React.lazy we&rsquo;re going to look at webpack&rsquo;s code splitting, one of its more powerful features. It is used to split up code in various bundles to reduce bundle sizes and load times. The most convenient way to achieve it is by using \u003Ca href=\"https:\u002F\u002Fwebpack.js.org\u002Fguides\u002Fcode-splitting\u002F#dynamic-imports\">\u003Cspan class=\"s2\">dynamic imports\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan class=\" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9f96z77zz74zz76z2qmz68zyz74zz86zz66zeggz75zz88zfjz89zl3z83zz89zz83zxz85zz66z\">. These\u003C\u002Fspan> are inline function calls from within modules\u002Fcomponents. An inline function call looks like this:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":215,"language":172,"body":216},"25270657","const User = import('.\u002FUser')\n\u002F\u002F Results in 1.chunk.js\n\nconst User = import(\u002F* webpackChunkName: 'User' *\u002F '.\u002FUser')\n\u002F\u002F Results in User.chunk.js",{"__typename":161,"id":218,"title":163,"body":219},"25270658","\u003Cp class=\"p1\">In React, just importing components like that will not work. This is where \u003Ccode>React.lazy\u003C\u002Fcode> comes in. This is a function that let's you use your dynamic imports as a regular components.\u003C\u002Fp>",{"__typename":170,"id":221,"language":172,"body":222},"25270659","const User = React.lazy(() => import('.\u002FUser'))",{"__typename":224,"id":225,"url":226,"title":227,"caption":163,"previewType":228},"CodePenBlockRecord","142973059","https:\u002F\u002Fcodesandbox.io\u002Fembed\u002Fw4486pj4w?codemirror=true&amp;view=split&amp;editorsize=50","CodeSandbox","codesandbox",{"__typename":161,"id":230,"title":231,"body":232},"25272236","Preloading","\u003Cp class=\"p1\">\u003Cspan class=\"s1\">Sometimes we know (or can try to predict) if a component is going to be used. In that case we want to use prefetch or preload, depending on the situation. You can indicate this to Webpack by using &lsquo;magic comments&rsquo;.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":234,"language":172,"body":235},"25272237","import(\u002F* webpackPrefetch: true *\u002F '.\u002FmyComponent')\n\n\u002F\u002F The above line results in a link tag appended to the \u003Chead>\n\u003Clink rel=\"prefetch\" as=\"script\" href=\"\u002Fstatic\u002Fjs\u002F2.chunk.js\">",{"__typename":161,"id":237,"title":163,"body":238},"25272238","\u003Cp class=\"p1\">\u003Cspan class=\"s1\">There are two options here:\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cul class=\"ul1\">\n  \u003Cli class=\"li2\">\u003Cspan class=\"s1\">\u003Cstrong>webPackPreload\u003C\u002Fstrong>: Indicating that the browser will need this resource soon after loading, using \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTML\u002FPreloading_content\">\u003Cspan class=\"s2\">link preloading\u003C\u002Fspan>\u003C\u002Fa>. This can be used at for example fonts, important images or scripts that are needed on the current page.\u003C\u002Fspan>\u003C\u002Fli>\n  \u003Cli class=\"li2\">\u003Cspan class=\"s1\">\u003Cstrong>webPackPrefetch\u003C\u002Fstrong>: uses browser idle time to load resources it might need in the future, using \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FLink_prefetching_FAQ\">\u003Cspan class=\"s2\">link prefetching\u003C\u002Fspan>\u003C\u002Fa>. This is used for fetching resources and put them in cache, so when they are used on the next page for example, they load instantly.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>",{"__typename":161,"id":240,"title":241,"body":242},"25272239","Suspense","\u003Cp class=\"p1\">\u003Cspan class=\"s1\">Components imported using \u003Ccode>React.lazy\u003C\u002Fcode> must be wrapped inside a Suspense tag. This is a feature of React that defers rendering until the lazy loaded component is fetched. Suspense needs to be placed anywhere above the lazy loaded component in the component tree. It provides a fallback for when a component inside it hasn&rsquo;t loaded yet, using the required &lsquo;fallback&rsquo; prop. \u003Cstrong>The beautiful thing about Suspense is that it doesn&rsquo;t have to be inside the component where something is imported\u003C\u002Fstrong>, but can also be higher up in the component tree. In the example you see how Suspense works when this is the case:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":224,"id":244,"url":245,"title":227,"caption":163,"previewType":228},"142972938","https:\u002F\u002Fcodesandbox.io\u002Fembed\u002Fv6k83yry1y?codemirror=true&amp;view=split&amp;editorsize=50",{"__typename":161,"id":247,"title":163,"body":248},"25272241","\u003Cp class=\"p1\">\u003Cspan class=\"s1\">If we run this example and take a look in our devtools, we see that the seperate components appear as their own javascript file. The loading state only gets replaced if all the components in the Suspense tag are loaded:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":250,"image":251,"caption":163,"fullWidth":147,"captionPosition":185},"GgB9yF5eSSCllU3OMo6J-Q",{"url":252,"alt":253,"width":254,"height":255},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1616164653-ezgif-3-e4776eb1ad57.gif","Chrome devtools showing how files are lazy loaded",600,335,{"__typename":161,"id":257,"title":258,"body":259},"25272395","Things to look forward to","\u003Cdiv>\n  \u003Cp class=\"p1\">\u003Cspan class=\"s1\">In the current stable release of React (17), Suspense is limited to use with \u003Ccode>React.lazy\u003C\u002Fcode>. This a nice feature for now, but what&rsquo;s coming is even more exiting: loading data with Suspense! This means we can use Suspense with fetching JSON or images. Having more control over loading states when data fetched will result in better loading states in UI&rsquo;s.\u003C\u002Fspan>\u003C\u002Fp>\n  \u003Cp class=\"p2\">\u003Cspan class=\"s1\">To learn more about Suspense and what&rsquo;s coming to react in the future, watch this amazing talk by Dan Abramov: \u003Ca href=\"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=nLF0n9SACd4\">\u003Cspan class=\"s3\">https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=nLF0n9SACd4\u003C\u002Fspan>\u003C\u002Fa>.\u003C\u002Fspan>\u003C\u002Fp>\n  \u003Cp class=\"p2\">\u003Cspan class=\"s1\">Further reading:\u003C\u002Fspan>\u003C\u002Fp>\n  \u003Cul class=\"ul1\">\n    \u003Cli class=\"li3\">\u003Cspan class=\"s4\">\u003Ca href=\"https:\u002F\u002Fwebpack.js.org\u002Fguides\u002Fcode-splitting\u002F\">\u003Cspan class=\"s5\">Webpack - Code splitting\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli class=\"li3\">\u003Cspan class=\"s4\">\u003Ca href=\"https:\u002F\u002Fmedium.com\u002F@jonatan_salas\u002Fa-walk-through-react-experimental-features-562baeb8a63a\">\u003Cspan class=\"s5\">A walk through React experimental features\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli class=\"li3\">\u003Cspan class=\"s4\">\u003Ca href=\"https:\u002F\u002Fmedium.com\u002Freloading\u002Fpreload-prefetch-and-priorities-in-chrome-776165961bbf\">\u003Cspan class=\"s5\">Preload, Prefetch And Priorities in Chrome\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fspan>\u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Fdiv>\n\u003Cul class=\"listtype-bullet listindent1 list-bullet1\">\u003C\u002Ful>",[],[],[],1776256146056]