React's Hidden Weapon : How Bundlers Slash HTTP Requests

Let's unbundle how bundlers reduce HTTP requests !!

Well do you know how exactly they reduce HTTP requests ? Below are a few questions that arise when someone is building their React concepts from scratch.

  • Is there a HTTP request everytime browser needs to access JavaScript/CSS file ?

  • Let’s say browser needs to access a JavaScript function funx() and
    image.png which is inlined.
    Are there going to be 2 HTTP requests ?

  • Or HTTP requests are only made to load files in the browser’s memory ?

  • Do we even need any HTTP request to access a function that is present in our JavaScript file once JS is already loaded to browser’s memory ?

Let’s find that out !! But before that try to answer these questions on your own.

1. Why Bundling Reduces HTTP Requests

To start, let's recap a fundamental concept:

When building a web application, the browser needs to download resources such as:

  • JavaScript files

  • CSS files

  • Images, fonts, etc.

Each of these resources typically requires a separate HTTP request (even if they are all related to your website), and each request comes with overhead, like DNS lookup, TCP handshake, and establishing secure connections (TLS/SSL), which can slow down page load times.

The Overhead of Multiple HTTP Requests:

Let's say you have a webpage with the following files:

  • app.js

  • utils.js

  • styles.css

  • logo.png

For the browser to load your page, it needs to:

  1. Request app.js from the server.

  2. Request utils.js from the server.

  3. Request styles.css from the server.

  4. Request logo.png from the server.

This means 4 separate HTTP requests for these resources. Even though these resources are related, each request involves a round-trip to the server, establishing connections, etc.

2. Bundling Reduces the Number of Requests:

Bundling works by combining multiple JavaScript and CSS files into one or a few larger files (known as a bundle), which dramatically reduces the number of HTTP requests.

Example:

Let’s assume you use a bundler like Webpack or Rollup. It can take:

  • app.js + utils.js → Bundle into bundle.js

  • styles.css → Bundle into bundle.css

After bundling:

  • The browser would only need to make 2 requests instead of 4:

    1. Request 1 for bundle.js (which now contains both app.js and utils.js).

    2. Request 2 for bundle.css (which contains the styles.css).

If the browser already has these files cached, then future page loads could require zero requests for these files, improving performance.

3. What Happens in Memory After Bundling?

When the browser loads the bundle.js and bundle.css, it loads them into memory (the browser's memory, specifically the JavaScript heap and CSSOM, respectively). Any function, variable, or image that's embedded (e.g., in a data URL) within these bundles can be accessed directly from memory without the need to make additional HTTP requests.

Let’s say I want to access 2 resources, funx() & and image.png :

  • If the JavaScript function funx() is in bundle.js, the browser can execute it directly from memory after it loads bundle.js.

  • If the image is base64-encoded and included in bundle.js or bundle.css, the browser can display it immediately by decoding the base64 string (without any additional HTTP requests).

Thus, after the first load, everything (JavaScript, CSS, and images) is available directly from the browser’s memory, which eliminates the need for additional HTTP requests.

💡
If the image is not inlined (i.e., the bundler copied the image file to an images/ directory and referenced it in bundle.js), the browser will make a separate HTTP request for the image, even though it's referenced inside the bundle.js.

For example, if the bundle.js contains code that references the image, the image might be located at /images/image1.png. The browser would then make a separate request to load the image:
Request 3: The browser sends an HTTP request to fetch /images/image1.png.

4. Exact HTTP Requests Made by the Browser (Without Bundling)

Let’s see exactly what happens without bundling. Suppose you have these separate files:

  • app.js

  • utils.js

  • styles.css

  • logo.png

Without Bundling:

The browser sends multiple HTTP requests to the server:

  1. Request #1: GET /app.js

    • The browser asks the server for the app.js file.
  2. Request #2: GET /utils.js

    • The browser then asks for utils.js.
  3. Request #3: GET /styles.css

    • The browser asks for the CSS styles.
  4. Request #4: GET /logo.png

    • The browser asks for the image logo.png.

5. Exact HTTP Requests Made by the Browser (With Bundling)

Now, let’s see what happens after bundling the resources into a single JavaScript bundle (bundle.js) and CSS bundle (bundle.css).

With Bundling:

Instead of making 4 separate requests, the browser now makes only 2 requests:

  1. Request #1: GET /bundle.js

    • The browser asks for the single bundle.js file, which contains both JavaScript files (app.js and utils.js), and possibly inline images or other resources.
  2. Request #2: GET /bundle.css

    • The browser asks for the bundle.css file, which contains all the CSS.

If the image is base64-encoded within the JavaScript or CSS file, no additional request is made for the image.

Congrats, you've just spared your website from the traffic jam!

6. Additional Benefits of Bundling:

  1. Reduced Round-Trip Time (RTT): Every separate HTTP request involves its own round-trip time (RTT). This is the time it takes for a request to travel from the browser to the server and back. If you make several requests, this time adds up. By bundling files into fewer requests, you minimize the number of round trips.

  2. Caching Efficiency:

    • When you bundle your files, you can take advantage of cache control headers. If you version your bundle.js file (e.g., bundle.[hash].js), the browser can cache that file, and only re-fetch it when it changes. This is more efficient than caching individual files because it reduces the number of cache invalidations.
  3. Compression: Bundled files (especially when minified and compressed) are typically smaller than the sum of individual files, which means less data is transferred, leading to faster load times.

  4. Tree Shaking: Modern bundlers like Webpack can also remove unused code through a process called tree shaking. This can reduce the size of the bundle even further, improving performance.


Example:

Without Bundling:

  • You have these 4 files:

    • app.js → 50 KB

    • utils.js → 30 KB

    • styles.css → 40 KB

    • logo.png → 20 KB

Total Data Transferred:

  • 4 HTTP requests with a total size of 140 KB.

Each HTTP request has its own overhead.

With Bundling:

  • You bundle all JS files (app.js + utils.js) into bundle.js80 KB

  • You bundle the CSS (styles.css) into bundle.css40 KB

  • The image (logo.png) is base64-encoded and included in the bundle.js20 KB

    Total Data Transferred:

    • 2 HTTP requests with a total size of 140 KB (the same total size, but fewer requests).

    • Additionally, once bundle.js and bundle.css are cached, no more requests are needed.

Conclusion:

  • Without bundling, the browser would send multiple HTTP requests for each individual file (JavaScript, CSS, images, etc.), leading to higher overhead due to more connections, DNS lookups, etc.

  • With bundling, the browser only sends a few requests (usually just 2 for JS and CSS) and loads everything it needs from those bundled files, reducing the overhead and improving the load speed of your website.

By combining multiple resources into fewer files (bundling), you reduce the number of HTTP requests, optimize the load time, and take better advantage of caching and compression.

I hope this clarifies the exact mechanism of bundling and how it reduces HTTP requests. Feel free to comment if you have any more questions or need further clarification !