This article starts with simple examples and analyzes the following three questions from packaging files: What is the webpack package file? How to be compatible with major modular solutions? What are the new features brought by webpack3?
A simple example
webpack configuration
// = { entry: './src/', output: { filename: '', path: (__dirname, 'dist') }, };
Simple js file
// src/ ('hello world');
Webpack packaged code
When you look at it, you will think, I will just have one line of code, do you pack so much for me? ? ? (Black question mark)
// dist/ /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(, module, , __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ = true; /******/ /******/ // Return the exports of the module /******/ return ; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ (exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __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, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { ('hello world'); /***/ }) /******/ ]);
Let's analyze this part of the code and simplify it first. In fact, the whole thing is a self-executing function, and then pass it into an array of modules.
(function(modules) { //... })([function(module, exports) { //.. }])
OK, what did you do when passing in the module array (actually, the comments are very obvious, I just translated them roughly)
/******/ (function(modules) { // webpackBootstrap /******/ // The module cache caches the loaded modules/******/ var installedModules = {}; /******/ /******/ // The required function referenced/******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache, return directly/******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) Construct a module and put it into the cache/******/ var module = installedModules[moduleId] = { /******/ i: moduleId, //Module id/******/ l: false, // Is it loaded?/******/ exports: {} // Exposed content/******/ }; /******/ /******/ // Execute the module function Pass in the module parameters and execute the module/******/ modules[moduleId].call(, module, , __webpack_require__); /******/ /******/ // Flag the module as loaded The tag module has been loaded/******/ = true; /******/ /******/ // Return the exports of the module Return the content exposed by the module/******/ return ; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) expose the module array/******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache exposes the cache array/******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports Define getter for ES6 exports/******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { // If exports itself does not contain the name attribute/******/ (exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules Resolve the conflict between ES module and Common js module, ES returns module['default']/******/ __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, property); }; /******/ /******/ // __webpack_public_path__ public path under webpack configuration/******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports Finally execute the entry module and return its exposed content/******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { ('hello world'); /***/ }) /******/ ]);
What is the overall process
- Passing in module array
- Call
__webpack_require__(__webpack_require__.s = 0)
Construct the module object and put it in the cache
Call module and pass in the corresponding parametersmodules[moduleId].call(, module, , __webpack_require__);
(Here exports will be modified by things inside the function)
Mark the module object has been loaded
Return the content exposed by the module (notice that the above function is passed in, you can modify the reference)
- Passed in module functions
module, , __webpack_require__
- During the execution process, variable exposure and reference are completed by modifying the references to the above three.
What is the webpack module mechanism?
We can check the webpack module on the official website
/concepts/mo…
The webpack modules can express their dependencies in various ways, as shown below:
- ES2015 import statement
- CommonJS requires() statement
- AMD define and require statements
- @import statement in css/sass/less file.
- Image links in style (url(...)) or HTML file (image url)
The powerful webpack module is compatible with various modular solutions and is non-opinionated.
We can write an example to find out
CommonJS
Modify src/
var cj = require('./'); ('hello world'); cj();
Add src/ to keep the previous examples unchanged
// src/ function a() { ("CommonJS"); } = a;
Run webpack again
/******/ (function(modules) { // webpackBootstrap //... Omit the code/******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { let cj = __webpack_require__(1); ('hello world'); cj(); /***/ }), /* 1 */ /***/ (function(module, exports) { function a() { ("CommonJS"); } = a; /***/ }) /******/ ]);
We can see that there is an imported file in the module array, and then the module function has an additional parameter __webpack_require__ to reference the file (__webpack_require__ was introduced in the previous section). Overall, the dependent module is modified, and then the main module executes the dependent module and obtains exports.
ES2015 import
Added src/
// src/ export default function b() { ('ES Modules'); }
Modify src/
// src/ import es from './'; ('hello world'); es(); constant,implementwebpack /******/ (function(modules) { // webpackBootstrap // ... Omit the code/******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; (__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1); ('hello world'); Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* default */])(); /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = b; function b() { ('ES Modules'); } /***/ }) /******/ ]);
We can see that they all become strict modes, and webpack automatically adopts
The performance is actually similar to CommonJS. It also passes in export and then modifyes it, and requires it in the main module.
We can see this
(__webpack_exports__, "__esModule", { value: true });
What is this for? In fact, it is to mark the current exports as the es module. Do you still remember the previous __webpack_require__.n? Let's take it out and take a look.
/******/ // getDefaultExport function for compatibility with non-harmony modules Resolve the conflict between ES module and Common js module, ES returns module['default']/******/ __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; /******/ };
To avoid conflicts with non-ES Modules? Where is the conflict?
In fact, if you see the source code of babel converting ES Modules, you will know that in order to be compatible with modules, ES Modules will be hung directly on, and then the __esModule attribute is added. When introducing it, determine whether it is a conversion module. If you are introducing modules, module['default'] is introduced, and if not, module is introduced.
Let's introduce a few more ES Modules to see the effect
// src/ export function es() { ('ES Modules'); } export function esTwo() { ('ES Modules Two'); } export function esThree() { ('ES Modules Three'); } export function esFour() { ('ES Modules Four'); }
We introduce more esTwo and esFour, but we do not use esFour
// src/ import { es, esTwo, esFour} from './'; ('hello world'); es(); esTwo();
Got it
/******/ (function(modules) { // webpackBootstrap // ... /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; (__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1); ('hello world'); Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* es */])(); Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["b" /* esTwo */])(); /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = es; /* harmony export (immutable) */ __webpack_exports__["b"] = esTwo; /* unused harmony export esThree */ /* unused harmony export esFour */ function es() { ('ES Modules'); } function esTwo() { ('ES Modules Two'); } function esThree() { ('ES Modules Three'); } function esFour() { ('ES Modules Four'); } /***/ }) /******/ ]);
Well, it's actually the same as before. What's the point of giving this example? Have you noticed the comments?
/* unused harmony export esThree */ /* unused harmony export esFour */
esThree is a module that we did not introduce, esFour is a module that we reference but did not use, webpack both marks them unused. In fact, if you use the webpack plugin uglify, the two unused codes of esThree and esFour will be eliminated (actually, it is tree-shaking)
AMD
Let's take a look at how webpack supports AMD
Added src/
// src/ define([ ],function(){ return { amd:function(){ ('AMD'); } }; });
Revise
// src/ define([ './' ],function(amdModule){ (); });
get
/******/ (function(modules) { // webpackBootstrap // ... Omit the code/******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(1) ], __WEBPACK_AMD_DEFINE_RESULT__ = function(amdModule){ (); }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && ( = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [ ], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return { amd:function(){ ('AMD'); } }; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && ( = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }) /******/ ]);
Let's look at the code first
function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; !( __WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function() { return { amd: function() { ('AMD'); } }; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && ( = __WEBPACK_AMD_DEFINE_RESULT__) ); })
Simply put, collect define Array and then place the return function to obtain dependencies according to the parameters.
apply to disassemble the array into parameters
Look at the module part
function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; !( __WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(1)], __WEBPACK_AMD_DEFINE_RESULT__ = function(amdModule) { (); }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && ( = __WEBPACK_AMD_DEFINE_RESULT__) ); }
In fact, it introduces the exposed {amd:[Function: amd]}
css/image?
CSS and image can also become webpack modules, which is shocking. This cannot be simply called through ordinary hack commonjs or function calls. This is anything to JS, and it needs to be implemented with the help of webpack loader.
For example, css is converted into a piece of js code. Through processing, when calling, you can use js to insert this piece of css into style. Image is similar. This part will not be explained in detail. Interested readers can study it in depth.
New features of webpack3
We can take a look at the performance of the new features of webpack3
You can see here for details/webpack/web…
Scope Hoisting
We can find that the module array is independent functions one by one, and then the closure refers to the corresponding content of the webpack main function. Each module is independent. The result is that the execution speed in the browser becomes slower. Then webpack3 learned the two tools Closure Compiler and RollupJS, connecting all closures into a closure, putting a function to make the execution faster, and the overall code volume will also be reduced.
We can actually look at the effect (it should be noted that this feature only supports ES Modules, not CommonJs and AMD)
Using the above example, configure, add new ()
const path = require('path'); const webpack = require('webpack'); = { entry: './src/', output: { filename: '', path: (__dirname, 'dist') }, module: { }, plugins: [ new (), ] };
Pack
/******/ (function(modules) { // webpackBootstrap // ... Omit the code/******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; (__webpack_exports__, "__esModule", { value: true }); // CONCATENATED MODULE: ./src/ function es() { ('ES Modules'); } function esTwo() { ('ES Modules Two'); } function esThree() { ('ES Modules Three'); } function esFour() { ('ES Modules Four'); } // CONCATENATED MODULE: ./src/ // src/ ('hello world'); es(); /***/ }) /******/ ]);
We can be surprised to find that there is no need, they are spliced into a function, good!😃
Magic Comments
Code splitting is one of the key features of webpack. When it comes to dynamically importing, webpack can be implemented using . Later, webpack2 supported the use of import() syntax that conforms to the ECMAScript proposal, but it has a disadvantage. It cannot specify the name of chunk chunkName. In order to solve this problem, Magic Comments appeared, which supports the use of comments to specify, as follows
import(/* webpackChunkName: "my-chunk-name" */ 'module');
summary
webpack is a powerful module packaging tool, which is excellent in handling dependencies and modules. This article explores the loading mechanisms of different module solutions based on file analysis, initially understands webpack, and explains the characteristics of webpack3. Of course, there are still many places to explore and explore webpack. Please stay tuned for future articles~ If you have any questions about this article, please leave me a message, and the editor will reply to everyone in time. Thank you very much for your support for my website!