preface
Postscript: Since webpack's knowledge base is too large, and Webpack is a very deep framework, so let's break it down. This time, we will talk about the basic principles and history of packaging, and then we will introduce it as deeply as possible: Tapable (5) tree-shaking (6) sourceMap (7) HMR
Front-end packaging, build, gulp, grunt, webpack, rollup, etc. It can be said that with the advent of Node, the front-end has become more and more complex, because JS code is no longer a weak language that only runs in the browser, and with it comes the ability to run on the server as well. I think the biggest benefit is that front-end projects can also be “engineered”, just like C, with pre-processing, compilation, assembly, linking capabilities. Of course javascript is an interpreted language, so there are no last three steps, and front-end packaging is more or less a preprocessing + modularization process.
Understanding front-end modularity
Why modularity: Is it all in main.js? How to reuse? How to collaborate on development? But JS is not like the others
scope
Global scope, local scope global: window, globalCopy the code
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<script src="./moduleA.js"></script>
<script src="./moduleB.js"></script>
<script src="./moduleC.js"></script>
</body>
</html>
Copy the code
// moduleA.js
var a = 1;
Copy the code
// moduleB.js
var a = 2;
Copy the code
// moduleC.js
var b = a + 1;
console.log('b = ', b);
Copy the code
Result :b = 3Copy the code
It’s obviously covered. What to do?
The namespace
//moduleA
var a = {
value: 1};Copy the code
//moduleB
var b = {
value: 1};Copy the code
//moduleC
console.log('moduleA的value', a.value);
console.log('moduleB的value', b.value);
Copy the code
Result: Value of moduleA1The value of moduleB2
Copy the code
It seemed to solve the above problem, but then came the problem:
a.value = 100;
Copy the code
It’s very easy to change one of the variables inside so we need to tweak it with scopes and closures
var moduleA = (function() {
var name = 'Nolan';
return {
myNameIs: function() {
console.log('Please call me', name); }}; }) ();Copy the code
This is an immediate function.
moduleA.myNameIs();
// Please call me Nolan
moduleA.name;
// undefined
Copy the code
It’s clearly exposing what needs to be exposed and hiding what needs to be hidden. So let’s optimize the way we write it
(function(window) {
var name = 'Nolan';
function myNameIs() {
console.log('Please call me', name);
}
window.moduleA = { myNameIs }; }) (window)
Copy the code
If you flick through the webpack packed code and compare it, doesn’t it look very similar?
To summarize
So we see a technology is step by step out, think about a handwritten JS inheritance is not also step by step to solve the problem, encounter new problems, and then solve the problem, the final result. Advantages:
- Scope encapsulation
- reuse
- Remove the coupling
modular
History
- AMD
- COMMONJS
- ES6 MODULE
AMD
define('moduleName'['lodash'].function(_) {
return function(a, b) {
console.log(a, b);
};
});
Copy the code
For example, requireJS later spawned the famous work Sea-.js (CMD).
COMMONJS
It was introduced in 2009 to standardize server-side development, not for browsers. So Nodejs later referenced this standard as well.
const moduleA = require('./moduleA');
exports.getSum = function(a, b) {
console.log(a + b);
}
Copy the code
As with AMD, there is an emphasis on introduced modules.
ES6 MODULE
Is very similar to COMMONS
import moduleA from './moduleA';
export function getName(name) {
return name;
}
Copy the code
Gulp and Grunt are automated build tools. Automation is emphasized here because they can do more than just packaging. Automation is their core purpose. The emergence of Webpack can be said to focus on packaging.
webpack
Let’s start with a little example
HTML, SRC /index.js, and SRC /util.js. NPM installs Webpack and the WebPack-CLI tool currently uses version 4.x.x. Tree-shake performance is optimized for V5, so the results of the build will be different. We’ll talk about what a tree-shake is later. index.html
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>My Webpack Test</title>
</head>
<body>
<script src="./dist/main.js"></script>
</body>
</html>
Copy the code
index.js
const num = require('./util');
function test() {
console.log('I'm a little test! ', num);
}
test();
Copy the code
util.js
exports.default = 123;
Copy the code
NPX webpack or./node_module/.bin/webpack at the root will generate dist/main.js
! function(e) {
var t = {};
function n(r) {
if (t[r]) return t[r].exports;
var o = t[r] = {
i: r,
l:!1.exports: {}};return e[r].call(o.exports, o, o.exports, n), o.l = !0, o.exports
}
n.m = e, n.c = t, n.d = function(e, t, r) {
n.o(e, t) || Object.defineProperty(e, t, {
enumerable:!0.get: r
})
}, n.r = function(e) {
"undefined"! =typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(e, "__esModule", {
value:!0
})
}, n.t = function(e, t) {
if (1 & t && (e = n(e)), 8 & t) return e;
if (4 & t && "object"= =typeof e && e && e.__esModule) return e;
var r = Object.create(null);
if (n.r(r), Object.defineProperty(r, "default", {
enumerable:!0.value: e
}), 2 & t && "string"! =typeof e)
for (var o in e) n.d(r, o, function(t) {
return e[t]
}.bind(null, o));
return r
}, n.n = function(e) {
var t = e && e.__esModule ? function() {
return e.default
} : function() {
return e
};
return n.d(t, "a", t), t
}, n.o = function(e, t) {
return Object.prototype.hasOwnProperty.call(e, t)
}, n.p = "", n(n.s = 0)
}([function(e, t, n) {
const r = n(1);
console.log("I'm a little test!", r)
}, function(e, t) {
t.default = 123
}]);
Copy the code
Let’s not worry about that big mess
Function (module){})([index.js, util.js])
Look at the structure and see if it is an immediate function! So, the great WebPack is simply implemented with the just-in-time functions mentioned earlier. What about all that code that wasn’t written by a human? Why does it look like a bird? Let’s first make the code readable.
Webpack –help shows the –mode parameter, development and production values. The default is production, and we can also see output like this when we run NPX webpack:
NPX webpack –mode=development
(function(modules) { // webpackBootstrap
// Define a cache
var installedModules = {};
// Call it webpack's require method running on the browser. The argument is the key in the argument to the function that executes immediately
function __webpack_require__(moduleId) {
If there is a cache, return the data in the cache
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// Happily put it in cache. Note that the exports object is defined here
var module = installedModules[moduleId] = {
i: moduleId,
l: false.exports: {}};// Execute the function
/ / think about, we in the IDE crazy mindless write import/require/exports/export these modules
// When running in the browser, the browser doesn't know it's dry, but what does the browser know?
Module. exports = module. Exports = module. Exports = module.exports = module
__webpack_require__ = __webpack_require__
// The require() argument is the module's path, i.e. the key in the immediate function argument
// Exports is an object
modules[moduleId].call(module.exports, module.module.exports, __webpack_require__);
/ / is not important
module.l = true;
// require(a file path), this file exports stuff
return module.exports;
}
// Add a dependency module to the built-in require object
__webpack_require__.m = modules;
// Add a cache for the built-in require object
__webpack_require__.c = installedModules;
// exports object adds a getter
__webpack_require__.d = function(exports, name, getter) {
if(! __webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true.get: getter }); }};// In the following example
__webpack_require__.r = function(exports) {
if(typeof Symbol! = ='undefined' && Symbol.toStringTag) {
/ / Object. The prototype. ToString. Call (exports) returns the Module
// The feeling is to look good
Object.defineProperty(exports.Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports.'__esModule', { value: true });
};
// To be honest, I'm not quite sure what this method does
ESM CJS interop. import("commonjs") will use it.
/ / address paste below: https://github.com/webpack/webpack/issues/11024
__webpack_require__.t = function(value, mode) {
if(mode & 1) value = __webpack_require__(value);
if(mode & 8) return value;
if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true.value: value });
if(mode & 2 && typeofvalue ! ='string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
return ns;
};
// In the following example
__webpack_require__.n = function(module) {
var getter = module && module.__esModule ?
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
};
// Contains attributes No
__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/ / is not important
__webpack_require__.p = "";
// require entry file
return __webpack_require__(__webpack_require__.s = "./src/index.js"); ({})// The entry method
"./src/index.js": (function(module.exports, __webpack_require__) {
eval("const num = __webpack_require__(/*! ./util */ \"./src/util.js\"); \n\nfunction test() {\n console.log(' I am a small test! ', num); \n}\n\ntest(); \n\n\n//# sourceURL=webpack:///./src/index.js?");
}),
// The introduced method
"./src/util.js": (function(module.exports) {
eval("exports.default = 123; \n\n//# sourceURL=webpack:///./src/util.js?"); })});Copy the code
It’s a little easier to read this time. I’ll write the function’s function in the comment.
So let’s try another ES6 MODULE with CJS and modify index.js
import { num } from './util';
function test() {
console.log('I'm a little test! ', num);
}
test();
Copy the code
And util. Js
exports.num = 123;
Copy the code
Let’s take a look at the results again. We won’t talk about the repetitions, focusing on the differences between __webpack_require__. N and __webpack_require__
(function (modules) { // webpackBootstrap
var installedModules = {};
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;
}
__webpack_require__.m = modules;
__webpack_require__.c = installedModules;
// 20. When you call exports.a, use the getter that you passed in
If you use import X from './util' in index.js;
// 22.console.log(X) is the getter for.a. Call it a day.
__webpack_require__.d = function (exports, name, getter) {
if(! __webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
enumerable: true.get: getter }); }};/ / 3. This Symbol. ToStringTag understood as when we Object. The prototype. ToString. Call (exports), returns [Object Module] type
__webpack_require__.r = function (exports) {
if (typeof Symbol! = ='undefined' && Symbol.toStringTag) {
Object.defineProperty(exports.Symbol.toStringTag, {
value: 'Module'
});
}
// 4. Exports object with an attribute that indicates that this file is ES6MODULE
// return to eval below
Object.defineProperty(exports.'__esModule', {
value: true
});
};
// Exports object is ES6Module.
// 12. If so, do we export default X as a default value and import X
In es6 module, export default X default = X;
// 14. Export default const X;
// 15. Default = const X
// 16. So we use getDefault to return exports.default for you
// the 17.d method overrides the getter method.
Getter is now getDefault(). 'a' is the name of one of the arguments we named
// 19. Let's take a look inside the.d method
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function getDefault() {
return module['default'];
} :
function getModuleExports() {
return module;
};
__webpack_require__.d(getter, 'a', getter);
return getter;
};
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty.call(object, property);
};
__webpack_require__.p = "";
return __webpack_require__(__webpack_require__.s = "./src/index.js"); ({})"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
// 1. Since we used import in index.js, WebPack is nice enough to insert a line of code in front of eval that calls r
// 2. Let's see what R did
// 6
// 7. The __webpack_require__.n method is called, passing the exports object from the imported file
// SRC /util.js/SRC /util.js/SRC /util.js /util.js
// 9. So his exports object does not have an attribute called __esModule
// 10
eval("__webpack_require__.r(__webpack_exports__); \n/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ \"./src/util.js\"); \n/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_0__); \n\n\nfunction test() {\n console.log(' I am a small test! ', _util__WEBPACK_IMPORTED_MODULE_0__[\"num\"]); \n}\n\ntest(); \n\n\n//# sourceURL=webpack:///./src/index.js?");
}),
This file does not use the ES6 module so it does not insert the __webpack_require__.r method as this one does
"./src/util.js": (function (module.exports) {
eval("exports.num = 123; \n\n//# sourceURL=webpack:///./src/util.js?"); })});Copy the code
It’s over… That makes sense
You’re smart enough to know that WebPack loads on demand. What would you do if you were asked to implement it? How many natural ways are there to separate files? Multiple entry? import()? Import (/* prefetch and preload*/) HTML
The principle of
We already know the product of Webpack, and we’ve analyzed the packaged product. What happens when you go from the original file to the built file?
To be continued