Analysis of the core concept of Webpack
These days we are thinking about creating a build tool by hand, but before we do that, we will try to comb through the concept of Webpack, after all, other mountains can attack the stone, which will help us to figure out how to design our own projects.
Introduction to the
Webpack is a static module bundler for modern JavaScript applications.
This is an introduction to Webpack, which is essentially a packer. Package JS modules into one or more. Implement the following capabilities in the code:
a.js + b.js + c.js. => bundle.js
Copy the code
The reason for the emergence of the packer, which I won’t go into here, is covered in many articles on the Internet. Let’s take a look at the core of webPack’s ability to pack multiple JS files into a single bundle.
Work backwards from the build artifacts to the core process
Webpack is a huge system, and analyzing the process from start to finish from a source point of view would be too complicated and unnecessary. After all, we are mainly learning core design concepts. So, we can try to work backwards from the results, from the packaged code, to analyze the idea of Webpack. With mode: ‘None’ and devtool: ‘cheap-source-map’, we can see that the packaged code looks something like this:
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports= = ='object' && typeof module= = ='object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports= = ='object')
exports["Magotan"] = factory();
else
root["Magotan"] = factory(); }) (window.function(){
return (function(modules){
// xxxx }) ([//xxxx[])'default']})Copy the code
It is obvious that this is an IIFE, which, when simplified, with specific implementation code, looks like this:
(function webpackUniversalModuleDefinition() {
exports["Magotan"] = (function (modules) {
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false.exports: {}}; modules[moduleId].call(module.exports, module.module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
return __webpack_require__(0); }) ([/* 0 */ // Module array list The array subscript is the module ID
(function (module, __webpack_exports__, __webpack_require__) {
__webpack_exports__["default"] = ({
getInstance: function getInstance() {
if (magotan === null) {
throw new Error('Not initialized instance, please initialize it through config first');
}
returnmagotan; }}),/ * 1 * /
(function (module.exports, __webpack_require__) {
var toObject = __webpack_require__(2);
var $keys = __webpack_require__(4);
__webpack_require__(21) ('keys'.function () {
return function keys(it) {
return $keys(toObject(it));
};
});
}),
// ...}); ] ) ['default']; }) ()Copy the code
As can be seen from the above code, we store all modules’ codes and dependencies in an array of modules. Then, we use webpack’s custom require method to recursively execute modules from the entry file, that is, the module with ID = 0.
So far we can analyze that the Core WebPack process is a two-step process
- Dependency Graphs are generated by recursive analysis in reslove Modules stage
- The Bundle phase assembles the artifacts of the previous phase into arrays and wraps them in functions, executing recursively from the entry file
subsequent
After making clear the design idea of Webpack, there are more concrete implementation problems we will encounter when making building tools, such as how to get the relationship between modules (using AST), how to ensure that there is no circular reference (using installedModules object) and so on. More will be covered in subsequent documents.