But for now, we must solve another pressing issue - our code is not very modular. Everything is defined inside a single <script> tag. Not only is this hard to read, but it is also not maintainable. We can't define every component in one file!
Furthermore, we are including libraries using <script> tags. Because some libraries depend on others (for example, react-dom depends on react), we must manually ensure our scripts are loaded in the right order.
We have already looked at CommonJS and ES6 modules when we discussed server-side modules. However, we must consider other factors when using modules on client-side code, such as:
- The size of each module. Dependencies are downloaded before the application is run. On the server, the application is only initialized once, after which it will keep running for a long time (weeks to years). Therefore, the initial time required for downloading dependencies is a one-time cost. On the client, however, these dependencies need to be downloaded each time a client loads the application. Therefore, it is much more important to keep the file size of the application and its dependencies to be as low as possible.
- How many separate requests are made? On the server, all dependencies reside on the server, and therefore importing a dependency costs virtually nothing. On the client, each request to the server is a new HTTP request, which requires a new TCP handshake. All these operations take a relatively long time, and thus we must ensure that as few requests are made to the server as possible.
- Asynchronous. We have already looked at CommonJS modules in Chapter 4, Setting Up Development Tools. CommonJS modules are loaded synchronously, this means modules are loaded in the order they are required inside the file/module being run. As a module can have hundreds of dependencies, it means it can take a long time to resolve and download all dependencies. This is not a problem for server applications, because after the initial time requirement, the server application would run for a long time without interruption. On the client, if A depends on B, and B depends on C, C cannot be downloaded until B is downloaded, because we simply cannot know in advance that B depends on C.
Because of these concerns, we need to use different tools to make our client-side application performant on the client. So let's spend some time to review them now.