Home > Web Front-end > JS Tutorial > Detailed explanation of webpack module and new features of webpack3

Detailed explanation of webpack module and new features of webpack3

小云云
Release: 2018-02-09 13:30:29
Original
1531 people have browsed it

This article starts with a simple example and analyzes the following three questions from the packaging file: What does the webpack packaging file look like? How to achieve compatibility with major modular solutions? What are the new features brought by webpack3? Webpack is a powerful module packaging tool that is excellent at handling dependencies and modules. This article starts from the analysis of bundle.js files to explore the loading mechanisms of different module solutions, to initially understand webpack, and to elaborate on the features of webpack3.

A simple example

webpack configuration

 // webpack.config.js
module.exports = {
 entry: './src/index.js',
 output: {
 filename: 'bundle.js',
 path: path.resolve(__dirname, 'dist')
 },
};
Copy after login

Simple js file

 // src/index.js
 console.log('hello world');
Copy after login

Webpack packaged code

Have a look at you I will think, I only have one line of code, how can you package so much for me? ? ? (Black question mark)

// dist/bundle.js
 /******/ (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.exports, module, module.exports, __webpack_require__);
/******/
/******/   // Flag the module as loaded
/******/   module.l = true;
/******/
/******/   // Return the exports of the module
/******/   return module.exports;
/******/  }
/******/
/******/
/******/  // 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)) {
/******/    Object.defineProperty(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;
/******/  };
/******/
/******/  // Object.prototype.hasOwnProperty.call
/******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(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) {
console.log('hello world');
/***/ })
/******/ ]);
Copy after login

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 in a module array

 (function(modules) { 
  //...
 })([function(module, exports) {
  //..
 }])
Copy after login

Okay, pass in the module What does the array do (actually the comments are very obvious, I just roughly translated it)

 /******/ (function(modules) { // webpackBootstrap
/******/  // The module cache 缓存已经load过的模块
/******/  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, //模块id
/******/    l: false, // 是否已经加载完毕
/******/    exports: {} // 对外暴露的内容
/******/   };
/******/
/******/   // Execute the module function 传入模块参数,并执行模块
/******/   modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/   // Flag the module as loaded 标记模块已经加载完毕
/******/   module.l = true;
/******/
/******/   // Return the exports of the module 返回模块暴露的内容
/******/   return module.exports;
/******/  }
/******/
/******/
/******/  // expose the modules object (__webpack_modules__) 暴露模块数组
/******/  __webpack_require__.m = modules;
/******/
/******/  // expose the module cache 暴露缓存数组
/******/  __webpack_require__.c = installedModules;
/******/
/******/  // define getter function for harmony exports 为ES6 exports定义getter
/******/  __webpack_require__.d = function(exports, name, getter) {
/******/   if(!__webpack_require__.o(exports, name)) { // 假如exports本身不含有name这个属性
/******/    Object.defineProperty(exports, name, {
/******/     configurable: false,
/******/     enumerable: true,
/******/     get: getter
/******/    });
/******/   }
/******/  };
/******/
/******/  // getDefaultExport function for compatibility with non-harmony modules 解决ES module和Common js module的冲突,ES则返回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;
/******/  };
/******/
/******/  // Object.prototype.hasOwnProperty.call
/******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/  // __webpack_public_path__ webpack配置下的公共路径
/******/  __webpack_require__.p = "";
/******/
/******/  // Load entry module and return exports 最后执行entry模块并且返回它的暴露内容
/******/  return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
console.log('hello world');
/***/ })
/******/ ]);
Copy after login

What is the overall process

  • Pass in the module array

  • Call __webpack_require__(__webpack_require__.s = 0)

Construct the module object and put it into the cache

Call the module and pass in the corresponding Parameters modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); (exports here will be modified by things inside the function)

Mark module object has been loaded

Return the content exposed by the module (notice that module.exports is passed in to the above function, the reference can be modified)

  • Pass in module, module.exports, __webpack_require__

    in the module function
  • During the execution process, variable exposure and reference are completed by modifying the references to the above three items

What is the webpack module mechanism?

We can go to the official website to take a look at the webpack module

doc.webpack-china.org/concepts/mo...

webpack modules can express their dependencies in various ways. A few examples are as follows:

  • ES2015 import statement

  • CommonJS require() statement

  • AMD define and require statement

  • @import statements in css/sass/less files.

  • Style (url(...)) or image link (image url) in HTML file ()

Powerful webpack module It is compatible with various modular solutions and is non-opinionated

We can write another example to find out

CommonJS

Modify src/index.js

var cj = require('./cj.js');
console.log('hello world');
cj();
Copy after login

Add src/cj.js and keep everything else unchanged from the previous example

// src/cj.js
function a() {
 console.log("CommonJS");
}
module.exports = a;
Copy after login

Run webpack again

/******/ (function(modules) { // webpackBootstrap
 //... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
let cj = __webpack_require__(1);
console.log('hello world');
cj();
/***/ }),
/* 1 */
/***/ (function(module, exports) {
function a() {
 console.log("CommonJS");
}
module.exports = a;
/***/ })
/******/ ]);
Copy after login

We can see that there are more imported files in the module array , and then the index.js module function has an additional parameter __webpack_require__ to reference the file (__webpack_require__ was introduced in the previous section). Overall, the dependent module modifies module.exports, and then the main module executes the dependent module and obtains the exports. Can

ES2015 import

Add src/es.js

// src/es.js
export default function b() {
 console.log('ES Modules');
}
Copy after login

Modify src/index.js

// src/index.js
import es from './es.js';
console.log('hello world');
es();
webpack.config.js不变,执行webpack
/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1);
console.log('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() {
 console.log('ES Modules');
}
/***/ })
/******/ ]);
Copy after login

We can see that they all become In strict mode, the performance of

automatically adopted by webpack is actually similar to that of CommonJS. It is also passed in export and then modified. Then require it in the main module.

We can see this

Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
Copy after login

What is this used for? In fact, it is to mark the current exports as an 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 解决ES module和Common js module的冲突,ES则返回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;
/******/  };
Copy after login

In order to avoid conflicts with non-ES Modules? Where is the conflict?

In fact, you will know this part if you see the source code of Babel converting ES Modules. In order to be compatible with the module, ES Modules will be directly hung on exports.default, and then the __esModule attribute will be added, and it will be judged once when it is introduced. Whether it is a conversion module, if so, introduce module['default'], if not, introduce module

We will introduce a few more ES Modules to see the effect

// src/es.js
export function es() {
 console.log('ES Modules');
}
export function esTwo() {
 console.log('ES Modules Two');
}
export function esThree() {
 console.log('ES Modules Three');
}
export function esFour() {
 console.log('ES Modules Four');
}
Copy after login

We will introduce more esTwo and esFour, But without using esFour

// src/index.js
import { es, esTwo, esFour} from './es.js';
console.log('hello world');
es();
esTwo();
Copy after login

, we get

/******/ (function(modules) { // webpackBootstrap
// ...
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1);
console.log('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() {
 console.log('ES Modules');
}
function esTwo() {
 console.log('ES Modules Two');
}
function esThree() {
 console.log('ES Modules Three');
}
function esFour() {
 console.log('ES Modules Four');
}
/***/ })
/******/ ]);
Copy after login

. Well, it’s actually the same as before. What’s the point of this example? Have you noticed the

/* unused harmony export esThree */
/* unused harmony export esFour */
Copy after login
## in the comments? #esThree is a module we have not introduced, esFour is a module we have referenced but not used, and webpack has marked them as unused. In fact, if you use the webpack plug-in uglify, through the marking, the two esThree and esFour will be marked. Unused code elimination (actually it is tree-shaking)

AMD

Let’s take a look at how webpack supports AMD

Add src/amd.js

// src/amd.js
define([
],function(){
 return {
  amd:function(){
   console.log('AMD');
  }
 };
});
Copy after login
Modify index.js

// src/index.js
define([
 './amd.js'
],function(amdModule){
 amdModule.amd();
});
Copy after login
Get

/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 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){
 amdModule.amd();
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
    __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __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(){
   console.log('AMD');
  }
 };
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
    __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ })
/******/ ]);
Copy after login
First look at amd.js to sort out the code

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() {
     console.log('AMD');
    }
   };
  }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
  __WEBPACK_AMD_DEFINE_RESULT__ !== undefined &&
  (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)
 );
})
Copy after login
To put it simply, collect define Array and then place the return function , obtain dependencies according to parameters

apply disassembles the array into parameters one by one

Look at the index.js module part again

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) {
    amdModule.amd();
  }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
  __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && 
  (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)
 );
}
Copy after login
In fact, it introduces the { exposed by amd.js amd:[Function: amd]}

css/image?

css and image can also become modules of webpack, which is shocking. This cannot be done through ordinary hack commonjs or The function call is simply called. This is anything to JS. It needs to be implemented with the help of webpack loader

像css就是转换成一段js代码,通过处理,调用时就是可以用js将这段css插入到style中,image也类似,这部分就不详细阐述了,有兴趣的读者可以深入去研究

webpack3新特性

我们可以再顺便看下webpack3新特性的表现

具体可以看这里medium.com/webpack/web…

Scope Hoisting

我们可以发现模块数组是一个一个独立的函数然后闭包引用webpack主函数的相应内容,每个模块都是独立的,然后带来的结果是在浏览器中执行速度变慢,然后webpack3学习了Closure Compiler和RollupJS这两个工具,连接所有闭包到一个闭包里,放入一个函数,让执行速度更快,并且整体代码体积也会有所缩小

我们可以实际看一下效果(要注意的是这个特性只支持ES Modules,是不支持CommonJs和AMD的)

使用上面的例子,配置webpack.config.js,增加new webpack.optimize.ModuleConcatenationPlugin()

const path = require('path');
const webpack = require('webpack');
module.exports = {
 entry: './src/index.js',
 output: {
 filename: 'bundle.js',
 path: path.resolve(__dirname, 'dist')
 },
 module: {
 },
 plugins: [
 new webpack.optimize.ModuleConcatenationPlugin(),
 ]
};
Copy after login

打包

/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
// CONCATENATED MODULE: ./src/es.js
function es() {
 console.log('ES Modules');
}
function esTwo() {
 console.log('ES Modules Two');
}
function esThree() {
 console.log('ES Modules Three');
}
function esFour() {
 console.log('ES Modules Four');
}
// CONCATENATED MODULE: ./src/index.js
// src/index.js
console.log('hello world');
es();
/***/ })
/******/ ]);
Copy after login

我们可以惊喜的发现没有什么require了,它们拼接成了一个函数,good!

The above is the detailed content of Detailed explanation of webpack module and new features of webpack3. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template