DEV Community

Cover image for Learning Webpack Concepts and Creating your Custom Webpack Plugin.
Jasmin Virdi
Jasmin Virdi

Posted on • Edited on

Learning Webpack Concepts and Creating your Custom Webpack Plugin.

In this post I will be covering the core concepts of Webpack which will help us to understand the basic mechanism and give us more clarity before building our own custom webpack plugin. So let's dive into details.

Why do we need webpack?

The tendency to write more JS code on the client side due to the enhanced browser features, faster Javascript engines and proliferation of mobile devices such as iPad has definitely shifted the trend from server side to client side development.
This leads to more Js code, modules and dependencies on the client side which will be dependent on one another.

For example, consider a file index.js which imports two other files file1.js and file2.js and file2.js is dependent on file1.js. In this case how the browser will know which file to load first such that it yields the desired result.

Alt Text

Solution

Webpack!💫

So the next question is how webpack solves this problem for us?

Webpack is a module bundler which builds and loads the modules synchronously. It converts dependencies into modules and make sure to pull the dependencies and modules at the right time in the correct scope. All the dependencies and modules are loaded in one file which will be downloaded.

This is the basic explanation of what is webpack but let's find out how webpack actually does all this work.

How webpack work on top of the hood?

In this section we will discuss the initial configuration that we will be using in the our webpack.config.js file to setup our client application.

  • Entry - It is used as the entry point for its dependency graph and create module as necessary.

Alt Text

In the above example bootstrap.min.ts is the first file to load and to kick-off your app. Webpack will use this file to build dependency graph.

  • Output - It defines the absolute path to distribute bundles.

Alt Text

  • Loaders - It tells the javascript how to resolve non-javascript modules after it has been used in the modules. It takes the resource file and returns the modified state.
modules: {
    rules: {
        {
            test: /\.ts$\,
            use: 'ts-loader'
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

You can similarly have many more loaders like css, babel etc. All the files other than js are converted into javascript module in some representation by these functional transformations. You can also filter through these modules by using properties like exclude, include, enforce etc.
There is also a way to chain loaders such that loaders that perform one operation will be transformed once and then you can chain them together.

rules: [{
    test: /\.less$\, 
    use: ['css-loader', 'style-loader', 'less-loader']
}]
Enter fullscreen mode Exit fullscreen mode
  • Plugins - An plugin is an ES5 class which implements an apply function and allow you to hook into the entire compilation lifecycle. The compiler uses it to emit events. It adds the new instance to the plugin key in config object.
var HelloWorldPlugin = require('hello-world');

module.exports = {
  // ... configuration settings here ...
  plugins: [new HelloWorldPlugin({ options: true })]
};
Enter fullscreen mode Exit fullscreen mode

This covers mainly what webpack does on top of the hood. There are multiple https://webpack.js.org/concepts/ which you can use while working on your applications.

How webpack under the hood?

In this section we will discuss what is webpack's architecture and how it works as a system bundler. In order to learn this we would start with a question "What is tapable"?

Tapable

It is the backbone of the plugin system. It allows us to mix your code with an existing class and make use of exiting functions like apply plugins parallel or apply plugins async etc, and emits events that we are listening to like the node event emitter. For example, simple basic plugin declaration would look like:

class BasicPlugin {
    apply(compiler) {
        compiler.apply('make', (compilation) => {
            console.log('I now have access to the compilation!!!!!!');
        });
    }
}

module.exports = BasicPlugin;
Enter fullscreen mode Exit fullscreen mode

A Tapable instance is a class/ object that extends Tapable and something you can plug into. There are some Tapable instances which are responsible for the working of webpack.

  1. Compiler - It is the central dispatch, it's kind of start or stop which delegates the top level events that are happening when webpack runs or finishes and it gets exposed.

  2. Compilation - It creates and runs the dependancy graph algorithm and works as the brain behind the webpack about what it does and what happens inside the compilation.

  3. Resolver - It justifies the term with what work it does, it majorly helps in finding files and dependencies like for example your index.js has imports specified with partial path or any other dependencies, resolver helps in finding the file from the information of partial file path import and build dependency graph.

  4. Module Factory - It takes the resolved request and collects source of that file and returns Module Object.

  5. Parser - It converts the raw source code into an AST such that it can be easily traversed. It starts by finding all require, imports and creates dependency object out of it.

  6. Template - It is responsible for binding data for your modules and creates code that we see in the bundle.

Alt Text

To summarise the whole process.

Webpack first reads the entry point and it go through resolver to verify that it exists or not. After that it goes through our normal module object that will pass through parser. Once the parser identifies the dependency type it passes it to loader if it is a non Javascript module whereas it simply collects dependencies and attach to the modules if it is a Javascript module. We have to then again check for dependencies that exists in the module and pass it through resolver, after this the entire cycle repeats until the complete dependency graph is build.

With this you have learnt how the webpack works internally.😁 💃

In the next post I will cover how I created my first webpack plugin to solve one of the problems which i was facing during building chrome extension.

Happy Reading! 📖

Top comments (12)

Collapse
 
shaijut profile image
Shaiju T • Edited

Nice, 😄, I am new to this, simple question. : Using webpack browser will know which file to load first. So does that mean webpack runs in browser or webpack generates the .JS file which does this job ? I think webpack doesn't run in browser.

Collapse
 
neo1380 profile image
Neo

You are right. Webpack doesnt run in the browser. browser understands only one language and its javascript. webpack helps us in generating the js bundles. on a high level, lets say that webpack bundles all our scripts into a single bundle.js. And this bundle.js is loaded into the browser when our application loads.

Collapse
 
jasmin profile image
Jasmin Virdi

Thanks @neo1380 , for summing it up. :)

@shaijut webpack helps to create module system which allows you to manage multiple files and dependencies on the client side. Browser don't have built in module resolver that is why we use Webpack. If you consider Node which is used on server side comes with built-in module resolver.

Thread Thread
 
shaijut profile image
Shaiju T

So lets say I have 2 .JS files, file1.js and file2.js, I want them to load in respective order. Now i use webpack to bundle both of these files to one file named as final-bundle.js. In client side using final-bundle.js browser will decide which file to load first ? Right ?

I have another question: Suppose I have 2 pages, Home page and Category page, So do we need to bundle each pages dependencies in separate bundle ? Like home-bundle.js and category-bundle.js. That should be the best practice ?

Thread Thread
 
jasmin profile image
Jasmin Virdi

Yes. So there is a dependency graph which helps to figure out which files need to be loaded first and what all modules are dependent on it. The entry file which you specify in the configurations is the entry point of dependency graph.

Most of the frameworks like Vue, React has App.js file which includes the root instance to render the app component. This file is generally used as entry point unless you want to configure it. You can pass multiple entry points to generate smaller bundles as well.

You can refer this for more details on configuring multiple entry points.

Thread Thread
 
shaijut profile image
Shaiju T • Edited

Nice writeup, Thank you all for the answers. Appreciate. :)

Collapse
 
vaibhavkhulbe profile image
Vaibhav Khulbe

Great article! Would like to feature it in my newsletter issue :)

Keep writing 😁

Collapse
 
jasmin profile image
Jasmin Virdi

Thank you so much, It means a lot!.

I'll make sure to subscribe it. :)

Collapse
 
palamnee profile image
palamnee

Loved the article Jasmin
Keep it up 😀

Collapse
 
jasmin profile image
Jasmin Virdi

Glad you like it! @palamnee 😄

Collapse
 
harshilparmar profile image
Harshil Parmar • Edited

Awesome !!! nice effort there.

Collapse
 
prashanthwagle profile image
Prashanth P Wagle • Edited

Informative Article. A one liner about NMF and AST would make the article clearer.