Webpack: How It Generates the Bundle

I recently started to use webpack, but I didn’t realize how it works.

I know it is not always necessary to know how everything works under the hood. But, certainly, getting a little bit more info about this can be helpful.

So I decided to dig deeper, to know what is the magic behind this.

 

Webpack Concepts

First of all I need to mention some webpack concepts.

Bundle

File that contains all the modules your application needs. In other words, it is how the application is packaged.

Dependency Graph

When a file depends on another webpack, it recursively builds a graph with all dependencies needed to generate the bundle.

Entry Point

It is the file that webpack uses to start resolving the dependency graph.

Output

The name of the file or files and the path where webpack will generate the bundles containing the dependency graph.

Loader

These modules are responsible for processing different kind of files. They are transformed into JavaScript modules that can be understood by webpack.

Later, the modules can be added to the bundle file.

Plugin

Plugins are modules that can perform many tasks, some examples are,

  • Extract text (CSS) from your bundles into a separate file.
  • Replace just the module changed instead of refreshing the whole page (Enable Hot Module Replacement).

Tapable

Tapable is a library that allows us to add plugins to a module. This is possible because every Class and Object that extends Tapable emits events that plugins can hook into to add functionality.

module.exports = options => {
return {
entry: {
'bundle': path.resolve(__dirname, './test.js')
},
output: {
filename: '[name].js',
}
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'çss-loader']
}
]
}
plugins: [
new customPlugin({
options: 'nothing'
})
]
}
}

The above is an example of a simple webpack configuration file,

entry

 

The entry file is called test.js.
output

 

The output file will be called bundle.js because of the [name].js in the filename property.
module

 

These are the loaders configuration.

How Do Loaders Work?

Webpack can deal only with JavaScript to generate the bundle. Loaders take care of transform them modules into JavaScript code.

We have to tell webpack what kind of files the loader will process, which directory to exclude (if needed), and the loader to use for that. All of this is included in the rules property.

If webpack finds a file import that matches the pattern for the name we indicated, it starts to build a bundle file. Webpack passes the file to the loader and the loader returns JavaScript code that is added to the bundle file.

Loaders are chainable. This means that the result of some loader processing could be the entry of another loader.

        {
test: /\.css$/,
use: [ 'style-loader', 'çss-loader']
}

This is an example of chainable loaders, this always works from right to left. The CSS-loader is in charge of reading CSS files. It resolves the references to another files (import and url). Then, the result is passed to the style-loader that inserts the CSS into the file.

One thing that loaders cannot do is to modify the actual build process. They don’t have access to the compiler and compilation process.

Luckily there are plugins!

When I was looking for an answer to how control the build process, plugins showed up.

Loaders just read the files, but they don’t have the control of the build process.

Plugins can be hooked into events of all instances of Classes that extends Tapable. The classes compiler and compilation are examples of this. You can access them to modify the behavior of the building process via plugins.

class CustomPlugin {
constructor(options) {
}
apply(compiler) {
compiler.plugin("done", function(stats) {
//code to execute after compiles has finished
});
}
}

The CustomPlugin example shows how to hook to the compiler’s done event.

When the compilation process is finished, the event done is triggered and the CustomPlugin done event callback is executed.

    plugins: [
new customPlugin({
options: 'nothing'
})
]

Plugins can be loaded creating a new instance and adding it to the plugins property inside webpack.config file

Finally …

Webpack loaders are the modules necessary to manage files that are not JavaScript.

Plugins allow us to interact directly with the tappable instances via hooks at building time. With this, we can tell webpack to do its magic to adapt to our requirements.

Share this post

Table of Contents