🐛🔨 The Contributors Guide to webpack — Part 3🎨 🖼

Building the Dependency Graph

The Contributors Guide to webpack is a multi-part publication series outlining the many ways that you can learn about, and contribute to the webpack open source project. You can read the first article in the series here!


Recap

In Part 1 of this series we learned about the packages that reside within both the webpack and webpack-contrib GitHub organizations! In Part 2, we discovered Tapable , learned that it is a ~230 line library similar to NodeJs’s EventEmitter , and found that it powers the entire [webpack] plugin system.

In addition to this, we learned how webpack creates tapable instances (Classes that extend Tapable ) and how [webpack] plugins register to them and execute their functionality. Finally, we learned about each tapable instance that exists in webpack and what their purpose is.

Building the Dependency Graph

In this article, we are going to combine what we’ve learned so far, and stitch together a high level explanation of how webpack builds the dependency graph.

The dependency graph is one of the key features of webpack, and we believe understanding how it works, can bring much insight to contributors and users alike.

Throughout this information you will find diagrams that come from my talk Everything’s a plugin: Mastering webpack from the inside out. These diagrams will serve as an aide to the material but we also recommend watching the first half of the talk as a companion to this guide.

Step 1: Initialize (Compiler)

Given that we already have a valid webpack configuration (known as the compiler options), the first tapable instance that we are going to encounter when webpack runs is known as the Compiler . Consider the Compiler as “central dispatch” because it is only in charge of triggering high level events such as "run" , "failed" , "done" . The Compiler will always return a Compilation, and other important tapable instances are attached such as NormalModuleFactory and ContextModuleFactory .

You can find the complete collection of my webpack source code annotations at thelarkinn/artsy-webpack-tour

After the Compiler has instantiated all plugins and objects needed to compile, it will return a new Compilation .

Step 2: Begin Compilation (Build the Graph)

After the Compilation (yes another tapable instance).

We describe the Compilation as your application’s dependency graph. To create a full graph, we must start from somewhere; a “root node” that branches out to all other “nodes”.

What we’re describing is the entry property in your configuration. Although we provide a path to the entry point, webpack still needs to confirm that path exists. Below will begin a recursive set of operations. (We’ll jump back to the recursion later)

Resolve

Any time that a raw request (path to a module) is provided — in this case its the entry point — webpack will first send this path information to the Resolver instance. The Resolver will use an enhanced NodeJs resolution pattern to to ensure the module at the given path exists, and then return additional information about that resolved module. This information includes file system stats, absolute path, and a unique ID for that resolved module.

This comes from my “Everything’s a plugin: Mastering webpack from the inside out” talk . In this slide, I describe how the Parser instance takes the module’s AST, and finds any “dependency statements” like require, and import, and then creates Dependency Objects that are attached to the module. You can think of these like edges for the graph!
  • Repeat the process: Once all Dependencies for that module have been found, we need to then “process” them. This is where the recursion occurs. Each dependency will need to go through these bullet points above to find the module it is pointing to.
A colorful narrative on building the dependency graph.

Now what?

With the information you have learned, pick one of the following Tapable instances mentioned above, and go to our core repository and find a plugin written for that instance. Observe how information and state flows between them and how the Parser leverages events to create Dependency sub-classes!!!

I personally love using chrome://inspect and use the Dedicated Node Debugging Tools to help me step through breakpoints and complex pieces of the source code.

Starting from somewhere that is familiar and understandable and branching out is one of the best ways to dive into a new code base!! To stick with the theme of this article, my recommendation would be Compiler.js or Compilation.js!

Learning the source, writing your own plugins, asking questions, and/or take notes!! These are all incredible ways that you can not only build your own skills, but equip yourself to be the next webpack contributor!!! And at the end of the day, have fun!!

Stay subscribed to our medium publication and stay tuned for the next part in this series as we learn what webpack does with this graph to create the bundles we see.


No time to help contribute? Want to give back in other ways? Become a Backer or Sponsor to webpack by donating to our open collective. Open Collective not only helps support the Core Team, but also supports contributors who have spent significant time improving our organization on their free time! ❤