on js, typescript, webpack, bundler, module, es5, es6, and __webpack_require__
‘What the heck does webpack (https://webpack.js.org) do?’
One of my biggest fears in my current projekt was to use a module bundler without the support of angular cli.
And so I thought lets have a look inside the ominous bundle.js.
Task of my webpack should be to bundle all ts files, transpile them and output a bundle.js which I can include in my webpage.
Our webpack.config.js looks like this.
Most parts should be pretty straight forward but lets have a look at what the end result has to do with my configuration.
So for testing I start with my ./src/main.ts
And of course ./models/clip.ts
Lets run webpack and see what bundle.js looks like
So what is this, and where is my code? Lets have a look at what this code does.
Simplified it does the following:
When bundle.js was loaded, the function function(modules) gets executed and initializes webpack, which basically means it sets up the __webpack_require__ function.
This function is the core when it comes to resolving modules by a module id. A module id is just the path to the filepath of the file containing the module.
Then webpacks does
We recognize that this load the file we specified as out entry module in webpack.config.js!
How is this done? Lets look at the __webpack_require__ function:
This function checks if the module was already loaded. Was it? No.
Then the function creates a new entry in the module cache and initializes it:
Then webpack executes the module, but wait what is a ‘module’ in this context? It is just an entry int the dictionary which was passed to the startup function we are currently inspecting. An we are using the entry with key ‘./src/main.ts’. And what are we doing with this entry? We are executing it:
modules[moduleId].call(thisArg, arg1, ...) is the same as modules[moduleId].apply(thisArg, [arg1, ...]) and runs a function - just in the case you are wondering what .call() does.
So what does the module function look like?
Well okay lets unwrap the eval:
Much better! It requires the clip module and creates a new clip object.
__webpack_require__: the __webpack_require__ function from above
__webpack_exports__: this i named ‘the exports of the module’ (see above)
Lets analyze this. What does this code do? At first we have this:
It executes the r function on the webpack_require function … object well however you name it in javascript. This r function was initialized in the block I named ‘some global initialization’. This is the r function:
Okay this only creates a new property __esModule={value: true} on ‘the exports of the module’.
Back to out module code. The next statement loads the clip module. Finally!!
So loading a module means assiging the return value of __webpack_require__ to a variable created by webpack. But what is the return value? If we have a look at __webpack_require__ it returns ‘the exports of the module’ and as we already know before returning __webpack_require__ calls the module code, this time of the code of the clip module, and inside the clip module ‘the exports of the module’ is __webpack_exports__.
Here is the clip module (already eval unwrapped):
We know __webpack_require__.r(__webpack_exports__); already.
But we dont know __webpack_require__.d(__webpack_exports__, "Clip", function() { return Clip; });. Uff what is this again:
At first a quick look at __webpack_require__.o = function(object, property), okay this checks if object has a property property.
Back to __webpack_require__.d. Ah okay it basically just creates a property with name name on ‘the exports of the module’ if there is not already a property with the same name. The getter of the property is the passed getter function. Fine, back to the clips module:
As we know __webpack_require__.d just creates a new property ‘Clip’ and the getter returns the Clip constructor.
So ‘the exports of the module’ contains a property which is the clip constructor. EASY!
Back to the main module:
We said that __webpack_require__ returns ‘the exports of the module’ and ‘the exports of the module’[“Clip”] means the Clip constructor.
Thats all the magic!
Conclusion
We showed how webpack bundles several typescript files, they are just ‘modules’ and a ‘module’ is an entry inside the modules dictionary with its filepath as key. The value ‘module’ entry is a functions which sets properties on ‘the exports of the module’ which then can be accessed by other ‘modules’ using the __webpack_require__ function.
Fun Fact
If you review the whole bundle.js file there is absolutely no code which handles the cases when a module was not found. But why? Simply because webpack knows that will never ever happen!