Hi, my name is Sungchul Won and I am a front-end developer at WhaTap. WhaTap's frontend is currently in the process of moving from Spring boot + Velocity to React, and I joined WhaTap in the middle of the process and am currently converting a lot of legacy code to React.
Since React is a Single Page Application (SPA) that draws the elements of the page with JavaScript rather than the traditional method of building a dome with HTML files for each page, it is very script-heavy, and importing many script files can cause a bottleneck in page loading, so we usually use Webpack to bundle the script files into a single file.
However, as the size of the service grew, the size of the bundle that combined all the script files became larger, and as the size of the bundle grew, the first entry of the page became slower. To solve this inconvenience, it was necessary to divide the code in the bundle, which was a set of all the code, into files that were a subset of specific scripts and modules called chunks using a technology called Code Splitting.
WhaTap's service uses react-router to load different components depending on the address, so let's see how to code split the chunk based on the components that are loaded according to the address.
First, check your current webpack's configuration file.
In the case of our service, the production build and development build settings were divided like this. It is good to separate the settings for the development environment and the deployment environment, but there are many overlaps in the two settings, and the same work needs to be done on both sides when adding content, and if the settings of the development environment and the deployment environment are different, bugs that cannot be checked in the development environment may occur when deploying, so we combined them into one company that works.
I combined the files into one and branched them with env so that I could set different settings for production build and development build depending on the build commands, but otherwise, I made all the settings the same because different settings can cause side effects, and I annotated them by simply identifying the roles that various plugins or settings play in the service.
I also added a plugin called webpack-bundle-analyzer to check the results of the current build.
We can see that all of the scripts on the frontend are contained in a file called main.bundle.js, with node_modules being the largest in size, and we can also see that node_modules contain duplicate dependencies, modules that are rarely used but are large in size, and so on.
You can see the file size in detail by hovering over it.
(Since our service also supports the product as a package in a closed network, it may take longer to decompress a gzip file if the network is fast but the performance of the PC is not good, so we are actually using a file of 21.85MB. We do plan to use gzip after testing).
We see that the bundle file is large, 21.85MB.
First, we decided that dynamic import is a good way to apply code splitting, as described in the official React documentation (https://reactjs.org/docs/code-splitting.html#import), so we wrote a HOC that performs dynamic import at the time the component is rendered.
Then, we modified the components used by the actual react-router to be dynamically imported using the HOC above.
I built it with the idea that the separation would be good, and the result was the following.
I could see the same result as before. (For the test, I tested without using the minimize option for a quick result check, so the capacity is displayed large.) I wondered why it didn't work and looked at the settings of webpack, and I saw that a plugin called dynamic-import-node is being used in babel.
It is a plugin that replaces the dynamic import syntax with require, but when I searched for it, I realized that it is a plugin used on the node server side, and I have not used dynamic import on the front side so far, so I uninstalled it without thinking.
You can see that a lot of the elements that were in main.bundle.js are gone, and the chunk files have the contents of those missing elements. Then I checked the result again with the minimize option, and the result was that
it was still a large size, but you can see that it's significantly smaller than it was at the beginning.
(I do not have a screenshot of this at the time, so I am replacing it with what it looks like on the WhaTap service today. It is a little better now than it was then).
You can see that the actual page also loads the main.bundle.js file, and fetches additional chunk files in context.
For a while, it was just feature development, bug fixing, feature development, bug fixing, and feature development, bug fixing, and I was completely ignorant of web packs, but I learned a lot and it was a fun (+hard) task to improve it like this, and when I used tools like bundle analyzer to visually show the situation, I saw many improvements besides splitting, so I will continue to work on many improvements.
This time, I tried to introduce Code Splitting in a really simple way, and in fact, what I've covered so far is just a really simple introduction, and there are many other things to cover, such as how to separate modules that are only used by a few specific modules, adjusting the timing of importing chunks, using dynamic import syntax in ES5, and so on, but I'll cover those things next time I have a chance.
Thank you for your patience with my lack of writing, and I will do my best to continue to be the front of WhaTap.
Thank you.
React official documentation https://reactjs.org/docs/code-splitting.html
Webpack official documentation https://webpack.js.org/guides/code-splitting