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.