Skip to content

Optimize Build Output w/ Code-splitting#2173

Draft
EjPlatzer wants to merge 16 commits intodevelopfrom
code-splitting
Draft

Optimize Build Output w/ Code-splitting#2173
EjPlatzer wants to merge 16 commits intodevelopfrom
code-splitting

Conversation

@EjPlatzer
Copy link
Contributor

This PR adds code-splitting that splits our bundled JS output for production builds into several files - roughly one per route.

Using the dynamic import() function that imports a JS Module only when called, we can split our code into several discrete chunks of code, as opposed to having it all in one giant file. This allows us to ensure that users only have to download the code needed for the pages they view, instead of downloading the code for the entire site even if, for example, they only visit the homepage.

This problem is technically caused by the bundling step in creating a production build, which transforms the thousands of files of source code into unified bundles of code in one file. Bundling is desirable because it prevents the browser from having to "waterfall" request the source code: i.e. request App.js from the server and parse that file, and then request and parse Home.js that is imported by App.js, and then request and parse CLWCredits.js that is imported by Home.js, etc.

The downside of bundling is that the bundled file can become so large that it takes a user-noticeable amount of time to download and includes code that may never run. Code-splitting lets us optimize in both directions, by bundling our code into files exactly sized to display one top-level route of the site each. So, the user gets only the code they need for the page they are currently viewing, but they get all that code in one request that serves one reasonably sized file.

For context, here are the JS files output for a production build before this PR, without code-splitting:

dist/assets/index-WsMC6urN.js 833.55 kB │ gzip: 292.94 kB
dist/assets/vendor-6iQ_XkZ0.js 2,665.92 kB │ gzip: 771.35 kB

And here are the JS files for the same version of the site but with code-splitting:

dist/assets/warning-HkAen8b2.js 0.09 kB │ gzip: 0.09 kB
dist/assets/useUserActions-TCrkzo0o.js 0.09 kB │ gzip: 0.10 kB
dist/assets/index-yGgHbn7e.js 0.16 kB │ gzip: 0.16 kB
dist/assets/contentManagement-vjZiW7b9.js 0.23 kB │ gzip: 0.17 kB
dist/assets/differenceInCalendarMonths-yjJgBVYV.js 0.25 kB │ gzip: 0.18 kB
dist/assets/Add-baZcjyX1.js 0.26 kB │ gzip: 0.23 kB
dist/assets/GetApp-eciZkhOe.js 0.27 kB │ gzip: 0.23 kB
dist/assets/ExpandMore-TP5SNTXV.js 0.28 kB │ gzip: 0.24 kB
dist/assets/Delete-oUdNR1KI.js 0.30 kB │ gzip: 0.26 kB
dist/assets/Clear-QgFswQXa.js 0.33 kB │ gzip: 0.25 kB
dist/assets/Email-qUAli72W.js 0.34 kB │ gzip: 0.27 kB
dist/assets/Edit-vehTvOv_.js 0.36 kB │ gzip: 0.28 kB
dist/assets/index-kBfANjNt.js 0.38 kB │ gzip: 0.26 kB
dist/assets/PostAdd-EsIQlCzU.js 0.44 kB │ gzip: 0.32 kB
dist/assets/index-PS0Hdf2A.js 0.45 kB │ gzip: 0.30 kB
dist/assets/index-rZN7dXBy.js 0.56 kB │ gzip: 0.39 kB
dist/assets/index-7USh5UeM.js 0.67 kB │ gzip: 0.38 kB
dist/assets/KeyboardArrowDown-kVII-tO1.js 0.72 kB │ gzip: 0.44 kB
dist/assets/differenceInSeconds-Hi72MION.js 0.81 kB │ gzip: 0.46 kB
dist/assets/session-Unj26T4A.js 0.81 kB │ gzip: 0.45 kB
dist/assets/utils-9qztO82O.js 0.83 kB │ gzip: 0.50 kB
dist/assets/index-45eiwgOi.js 0.94 kB │ gzip: 0.52 kB
dist/assets/address-YLl0dr1t.js 0.98 kB │ gzip: 0.57 kB
dist/assets/activity-zU95R54a.js 1.19 kB │ gzip: 0.58 kB
dist/assets/index-sbLSHlT7.js 1.34 kB │ gzip: 0.72 kB
dist/assets/membership-SM9SSgiQ.js 1.36 kB │ gzip: 0.66 kB
dist/assets/index-T5VIeFUB.js 1.38 kB │ gzip: 0.66 kB
dist/assets/peopleSearch-Wuw1ypTR.js 1.54 kB │ gzip: 0.76 kB
dist/assets/index-aC453RYs.js 1.95 kB │ gzip: 0.75 kB
dist/assets/request-bBQgIgcT.js 2.06 kB │ gzip: 0.89 kB
dist/assets/parseISO-IM_NLZL1.js 2.70 kB │ gzip: 1.19 kB
dist/assets/event-gPX7gdiJ.js 4.51 kB │ gzip: 1.81 kB
dist/assets/index-VA4f3W9y.js 4.87 kB │ gzip: 1.77 kB
dist/assets/index-4-KPABxG.js 5.53 kB │ gzip: 2.51 kB
dist/assets/index-6OVUORTR.js 5.64 kB │ gzip: 1.83 kB
dist/assets/index-CP-APYKM.js 7.59 kB │ gzip: 2.94 kB
dist/assets/index-K-AliMYx.js 8.03 kB │ gzip: 2.84 kB
dist/assets/index-sSgjSjhi.js 8.37 kB │ gzip: 3.23 kB
dist/assets/index-ImT7E9c3.js 9.25 kB │ gzip: 5.27 kB
dist/assets/index-tFzE8uGz.js 9.32 kB │ gzip: 3.08 kB
dist/assets/format-vYysxyT3.js 9.88 kB │ gzip: 2.58 kB
dist/assets/index-9aquEFQV.js 10.69 kB │ gzip: 3.54 kB
dist/assets/index-iVoJv6k8.js 22.43 kB │ gzip: 7.47 kB
dist/assets/index-iucRGWrt.js 23.81 kB │ gzip: 7.07 kB
dist/assets/index-ayO2OE8d.js 27.27 kB │ gzip: 7.54 kB
dist/assets/parse-M--5VP2u.js 30.59 kB │ gzip: 7.55 kB
dist/assets/lib-kSuJiXcy.js 32.58 kB │ gzip: 11.97 kB
dist/assets/react-cropper.es-gsAqu7K8.js 41.17 kB │ gzip: 13.46 kB
dist/assets/index-BLCj790W.js 42.28 kB │ gzip: 14.70 kB
dist/assets/index-1AQZCyb_.js 47.29 kB │ gzip: 14.16 kB
dist/assets/index-GkeEmQIf.js 48.66 kB │ gzip: 17.21 kB
dist/assets/input-2_7jd6Gq.js 59.11 kB │ gzip: 16.05 kB
dist/assets/index-ZEPx06S7.js 77.14 kB │ gzip: 20.72 kB
dist/assets/index-1zeCq1SL.js 219.62 kB │ gzip: 72.70 kB
dist/assets/index-Fml97MKY.js 263.79 kB │ gzip: 83.34 kB
dist/assets/index-fjClROUH.js 317.07 kB │ gzip: 92.99 kB
dist/assets/index-HORelsw6.js 358.69 kB │ gzip: 121.35 kB
dist/assets/index-BC2_gl-e.js 366.35 kB │ gzip: 71.48 kB
dist/assets/index-FHEayoXN.js 386.91 kB │ gzip: 158.47 kB
dist/assets/vendor-h-SsZ3sH.js 1,021.64 kB │ gzip: 300.99 kB

We go from two VERY large JS files to a number of more reasonably-sized JS files. The vendor.js file is still noticeably large unfortunately, but it is less than half it's previous size. There are some scripts in the code-split build that don't seem like they need to be in their own files. But I think that code-splitting at the top-level routes is a good enough starting point for this behavior.

This plugin is deprecated because the underlying issue is fixed in vite v5
Using the dynamic `import()` function that imports a JS Module only when called, we can split our code into several discrete chuncks of code, as opposed to having it all in one giant file. This allows us to ensure that users only have to download the code needed for the pages they view, instead of downloading the code for the entire site even if they only visit the homepage.

This problem is technically caused by our bundler, which transforms the thousands of files of source code into unified bundles of code in one file. Bundling is desirable because it prevents the browser from having to "waterfall" request the source code: i.e. request App.js from the server, and then request Home.js that is imported by App.js, and then request CLWCredits.js that is imported by Home.js, etc. The only downside is that the bundled file can become so large that it takes a user-noticeable amount of time to download, and includes code that will never run because the user only visits a small portion of the site. Code-splitting lets us optimize in both directions, by bundling our code into files exactly sized to display one top-level route of the site each. So the user gets only the code they need for the page they are currently viewing, but they get all that code in one request that serves one reasonably-sized file.
@EjPlatzer EjPlatzer self-assigned this Feb 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant