Module Bundlers Explained

Module Bundlers Explained

·

5 min read

Module Bundlers - If you are a web developer, you might have heard the term module bundler every now and then. Today, most modern and complex web applications use a module bundler in their tooling, so what really are they?

A module bundler is a tool that takes pieces of JavaScript and their dependencies and bundles them into a single file, usually for use in the browser. So, all the javascript and CSS files will be bundled into a single javascript and CSS file respectively

webpack.pngSource: Webpack

What is the need?

Back in the old days, all we needed to build websites was plain HTML, CSS, and javascript. So, if we had any script and CSS files, we would link them in the HTML file as follows

<html>
<head>
  <link rel="stylesheet" href="style.css"> <!-- Importing the CSS file -->
</head>
<body>
  <script src="app.js"></script> <!-- Importing the javascript file -->
</body>
</html>

But, as applications grew bigger and got more complex, the amount of javascript that was written also increased. This meant that the number of javascript files that needed to be imported using the <script> tag also increased. The HTML file started to look like this👇

<html>
<head>
  <link rel="stylesheet" href="style.css"> <!-- Including the CSS file -->
</head>
<body>
  <script src="app.js"></script> <!-- Including the javascript files -->
  <script src="foo.js"></script>
  <script src="bar.js"></script>
  <script src="xyz.js"></script>
  <script src="pqr.js"></script>
  <script src="abc.js"></script>
</body>
</html>

In an ideal scenario, you're are looking at a lot more <script> tags than the example above.

Writing modular code was also challenging since the module system in javascript didn't exist back in the day.

*Note - Currently module systems like CommonJS and ES Modules do exist, but its outright use without a bundler is sparse because of limited browser support

This introduced a host of problems

1. Maintainability - Having to manually keep track of all the files imported using <script> tags started to become a challenge. When we are importing javascript files using the <script> tag, the order in which we have to import them is important. For example, Let's say you have a file foo.js which has a variable a, and we are using that variable in bar.js. Now since a is declared in foo.js, we would first need to import foo.js and then bar.js. Imagine having to keep track of this when you have a large number of files.

2. Variable Naming - When we import javascript files using <script> tags, all the variable and function declarations exist in the global scope. This means that if we declare a variable/function in one file, we cannot declare that variable/function with the same name in any other file.

3. Network Calls - When there are multiple import statements for javascript files and CSS files, a network call is made to download each one of those files. This means if we have 10 javascript files, 10 network calls are made to download those files and make the application work. This negatively impacts the performance of the application as the number of files that need to get downloaded increases.

This is where a module bundler comes into the picture. Let's take a look at how they work.

Working of a module bundler

The way a module bundler works is, it starts from an entry point(a file). Most module bundlers have a default place where they look for the entry point which can be changed using a configuration file. Starting from the entry point, it starts building a dependency graph recursively.

Let's say we have a file index.js. It imports the file app.js. Now, app.js imports the package lodash and a file util.js. Lodash itself might depend on many other smaller packages. The mapping of all these files and packages is what we call a dependency graph. Any file that is dependent on another file or package, is treated as a dependency. *Dependency graph is not limited to javascript files and can contain other files such as CSS, images, and fonts

dep_graph.png

After the dependency graph is created, it bundles all the code into one(or more) files, which is then loaded by the browser. Apart from handling dependencies for us and solving the above-mentioned problems and making our lives easier, bundlers can do much more. Let's take a look at them.

1. Transpilation - If you like writing modern javascript code, chances are it won't be supported in older browsers. Bundlers can help solve this problem by transpiling your modern javascript code to older javascript using a transpiler like Babel.

2. Code-splitting - As we understood, bundlers create a bundle containing all our code based on the dependency graph. Sometimes, the size of this bundle can be quite large. This can negatively impact the performance since it will take longer to download the bundle. To help solve this, bundlers can do code-splitting. Code-splitting is where the bundle is divided into smaller bundles, which can be loaded dynamically/on-demand, thus improving performance.

3. Tree Shaking - Modern web applications use a lot of packages to achieve various things. These packages can be huge in size. Tree-shaking is the process of removing unused exports from these packages, rather than bundling the whole package.

4. Support for native module system - Most bundlers support the use of native javascript import/export statements(ES Modules) out of the box.

5. Live-Reload - Bundlers support live reloading of the application whenever we make a change in any file

Let's take a look at some of the popular module bundlers.

1. Webpack - Webpack is the most popular module bundler. It works like a module bundler should work. It builds a dependency graph before bundling the code. Webpack only supports javascript and JSON out-of-box, but other file types are supported by the use of loaders.

2. Rollup - Rollup is another module bundler for javascript. It only supports javascript by default, but other file types are supported using plugins. A configuration file is not needed to use rollup, but according to official documentation, they are powerful and convenient and thus recommended.

3. Parcel - Parcel is a lightning-fast bundler with out-of-box support for javascript, CSS, HTML, file assets, and more -without the need for plugins. It needs zero configuration and hence, there is no need for a configuration file. Compared to the above two options, parcel is the easiest to use and provides the best developer experience.

Conclusion

That's it for now. We looked at a brief history of how module bundlers came to be, and how they work. The best way to learn more about them is to actually use them. If you are a beginner I'd recommend using Parcel and if you're looking to get more advanced you can try webpack.