Webpack Deep Dive Part 2: The Introduction
By: Randall Naar
Tags: Front End Development, Web Development, Tools, Webpack, Open Source

If you’ve been following my blog posts you’ll know that I’ve been exploring the webpack codebase quite extensively both as a challenge to myself and a way to educate others on looking at open source code. My last post covered hooks and briefly mentioned the framework that underlies webpack’s architecture, ‘Tappable’. This post builds off of that knowledge and will investigate the early stages of the webpack execution pipeline. Along the way I’ll also share the thought process I use to understand foreign codebases and give feedback on what I like and don’t like about how the code is structured.

Setup

Similar to how a mountain climber thinking of climbing Mt.Everset might bring a compass and map to keep them from getting lost, we must bring our own tools to navigate the webpack codebase for pretty much the same reasons. The tools I’m recommending for use are ‘git’ and ‘Visual Studio Code’.

Git

Git will be used to pull down the code and update it to new versions. It’s also my preferred way to download the codebase although you can also download the zipped codebase directly from the github website as well.

Visual Studio Code

I mostly use Visual Studio Code for the all-important task of search. It has handy shortcuts for searching for files by name along with the functionality to search the code for classes, variables, and functions.

Where to Start

I’ll begin my exploration of the webpack repo with what I already know about the library. In this case that knowledge is in the form of webpack’s Node API. The example shown imports webpack as a function and calls it. It needs 2 parameters — the options object and a callback function.

Working our way back from what we know, a good first step might be to search the codebase for ‘webpack’. It would make sense that a ‘webpack.js’ file exists since that’s what we used within the require statement for importing. Visual Studio code’s file search can be used for this using the shortcut Ctrl+p for Windows and Cmd+p for Mac (assuming the repo has already been opened).

<trigger-warning>Yes, I use a red themed VS Code 🙂</trigger-warning>

Within the repo there’s a file named ‘webpack’ inside the ‘lib’ folder. The webpack.js file has the ‘webpack’ function definition near the bottom and the export statement right below it. We can verify that this is the same function we imported using the Node API by just looking at the function signature. It takes the the options object and a callback function which are the same 2 parameters we saw in the example. With that we’ve reached our first milestone — finding the connection between webpack’s public facing api and where that api is defined within the repo.

The Beginning

Looking at the webpack.js file here, I decided to abstract the code into short comments and pseudocode like so:

Code from lib/webpack.js. I removed the imports and (ironically) some comments for clarity.

The reason for the code summarization above is to get a general idea of what each function does in order to get a better grasp of the entire program’s flow of control. Unfortunately I ran into a roadblock going through compiler.js’s 2 ‘run’ methods seen down below:

Besides my inherent disdain for most inline functions, one thing that cannot be overlooked is the naming of the inline function ‘run’ within a function of the same name! This leads to confusing code and raises another potential code smell — bad naming.

Martin Fowler says this about functions and their names in his book Refactoring:

If you have to spend effort looking at a fragment of code and figuring out what it’s doing, then you should extract it into a function and name the function after the “what.” Then, when you read it again, the purpose of the function leaps right out at you, and most of the time you won’t need to care about how the function fulfills its purpose (which is the body of the function).

The function name ‘run’ unfortunately does not give me this convenience of ignoring it’s implementation as I can’t imagine someone would be able to differentiate the implementation of the 2 run methods by just looking at their function signatures.

Moving on, the second ‘run’ method called from the code above leads into a call to ‘this.compile’:

The Struggle

On my first look through of this code I was floored. Mostly because I didn’t know about Tappable, but even after I found out about Tappable, I knew looking for hooked functions would be a chore.

All of the hooked functions have implicit invocations which require us to search the code for where these functions have been ‘tap’ped (or added) to the hooks.

The strangest thing about the ‘run’ and ‘compile’ code snippets is that only a couple methods have been called in the execution cycle when compiler.js is reached! This begs the question of when these functions were hooked in the first place. As I soon came to find out, it’s done in the intuitively named ‘WebpackOptionsApply’s ‘process’ method.