zoukankan      html  css  js  c++  java
  • 深入浅出的webpack4构建工具---Scope Hoisting(十六)

    一:什么是Scope Hoisting? 它有什么作用?
    Scope Hoisting 它可以让webpack打包出来的代码文件更小,运行更快,它可以被称作为 "作用域提升"。是在webpack3中提出来的,当然现在webpack4也是支持的。

    在介绍之前,我们还是来和之前一样,看看我们项目整个目录架构如下:

    ### 目录结构如下:
    demo1                                       # 工程名
    |   |--- dist                               # 打包后生成的目录文件             
    |   |--- node_modules                       # 所有的依赖包
    |   |--- app
    |   | |---index
    |   | | |-- views                           # 存放所有vue页面文件
    |   | | | |-- home.vue
    |   | | | |-- index.vue
    |   | | | |-- xxx.vue
    |   | | |-- components                      # 存放vue公用的组件
    |   | | |-- js                              # 存放js文件的
    |   | | |-- app.js                          # vue入口配置文件
    |   | | |-- router.js                       # 路由配置文件
    |   |--- views
    |   | |-- index.html                        # html文件
    |   |--- webpack.config.js                  # webpack配置文件 
    |   |--- .gitignore  
    |   |--- README.md
    |   |--- package.json
    |   |--- .babelrc                           # babel转码文件

    首先我们在 app/index/js 下新建 index.js 代码如下:

    export default 'xxxx';

    然后在我们的入口文件 app/index/app.js 代码如下:

    import index from './js/index';
    console.log(index);

    然后运行 npm run build 打包后,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, { enumerable: true, get: getter });
    /******/    }
    /******/  };
    /******/
    /******/  // define __esModule on exports
    /******/  __webpack_require__.r = function(exports) {
    /******/    if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
    /******/      Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
    /******/    }
    /******/    Object.defineProperty(exports, '__esModule', { value: true });
    /******/  };
    /******/
    /******/  // create a fake namespace object
    /******/  // mode & 1: value is a module id, require it
    /******/  // mode & 2: merge all properties of value into the ns
    /******/  // mode & 4: return value when already ns object
    /******/  // mode & 8|1: behave like require
    /******/  __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 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
    /******/    return ns;
    /******/  };
    /******/
    /******/  // 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 = "./app/index/app.js");
    /******/ })
    /************************************************************************/
    /******/ ({
    
    /***/ "./app/index/app.js":
    /*!**************************!*
      !*** ./app/index/app.js ***!
      **************************/
    /*! no exports provided */
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    /* harmony import */ var _js_index__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./js/index */ "./app/index/js/index.js");
    
    
    console.log(_js_index__WEBPACK_IMPORTED_MODULE_0__["default"]);
    
    /***/ }),
    
    /***/ "./app/index/js/index.js":
    /*!*******************************!*
      !*** ./app/index/js/index.js ***!
      *******************************/
    /*! exports provided: default */
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    
    /* harmony default export */ __webpack_exports__["default"] = ('xxxx');
    
    /***/ })
    
    /******/ });
    //# sourceMappingURL=bundle.js.map

    如上代码我们没有使用 Scope Hoisting 功能,输出如上那么多代码,下面我们来看看引入 Scope Hoisting 功能,打包后的代码;

    要使用 Scope Hoisting 功能,首先我们需要 的是我们JS文件都使用ES6的语法来编写的,否则它是不会生效的。还是上面的代码不变。

    使用 Scope Hoisting(编写的代码需要支持ES6规范)

    Scope Hoisting 是webpack内置的功能,只要配置一个插件即可,如下在webpack.config.js 代码如下配置:

    module.exports = {
      plugins: [
        // 开启 Scope Hoisting 功能
        new webpack.optimize.ModuleConcatenationPlugin()
      ]
    }

    然后执行npm run build 打包后的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, { enumerable: true, get: getter });
    /******/    }
    /******/  };
    /******/
    /******/  // define __esModule on exports
    /******/  __webpack_require__.r = function(exports) {
    /******/    if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
    /******/      Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
    /******/    }
    /******/    Object.defineProperty(exports, '__esModule', { value: true });
    /******/  };
    /******/
    /******/  // create a fake namespace object
    /******/  // mode & 1: value is a module id, require it
    /******/  // mode & 2: merge all properties of value into the ns
    /******/  // mode & 4: return value when already ns object
    /******/  // mode & 8|1: behave like require
    /******/  __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 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
    /******/    return ns;
    /******/  };
    /******/
    /******/  // 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 = "./app/index/app.js");
    /******/ })
    /************************************************************************/
    /******/ ({
    
    /***/ "./app/index/app.js":
    /*!**************************************!*
      !*** ./app/index/app.js + 1 modules ***!
      **************************************/
    /*! no exports provided */
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    
    // CONCATENATED MODULE: ./app/index/js/index.js
    
    /* harmony default export */ var js = ('xxxx');
    // CONCATENATED MODULE: ./app/index/app.js
    
    
    console.log(js);
    
    /***/ })
    
    /******/ });
    //# sourceMappingURL=bundle.js.map

    如上代码可以看到,开启 Scope Hoisting后,函数声明由两个变成了一个,app/index/js/index.js 代码直接被注入到 app.js里面去了,如上代码 var js = ('xxx');

    因此 启用 Scope Hoisting的优点如下:
    1. 代码体积会变小,因为函数声明语句会产生大量代码,但是第二个没有函数声明。
    2. 代码在运行时因为创建的函数作用域减少了,所以内存开销就变小了。

    具体的可以看官网(https://webpack.js.org/plugins/module-concatenation-plugin/)

    但是对于有很多第三方库并没有使用ES6模块语法的代码,webpack它会降级处理这些非ES6编写的代码,不使用 Scope Hoisting 优化。

    因此在webpack中还需要加上如下代码配置:

    module.exports = {
      resolve: {
        // 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
        mainFields: ['jsnext:main', 'browser', 'main']
      },
    };

    我们可以在启动webpack时候带上 --display-optimization-bailout 参数,在输出日志中就会包含类似如下的日志:如下图

    其中的 ModuleConcatenation bailout 告诉了你哪个文件因为什么原因导致了降级处理。

    因此在webpack中所有的配置代码如下:

    module.exports = {
      resolve: {
        // 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
        mainFields: ['jsnext:main', 'browser', 'main']
      },
      plugins: [
        // 开启 Scope Hoisting 功能
        new webpack.optimize.ModuleConcatenationPlugin()
      ]
    };
  • 相关阅读:
    简单明了的带你理解springboot原理和三大核心注解
    Spring Boot(一):入门篇
    【Mysql优化】聚簇索引与非聚簇索引概念
    Mysql索引原理与优化
    Mysql全文索引的使用
    索引的优缺点,如何创建索引
    184 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 04 例:字符串与byte(即:字节)数组间的相互转换
    183 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 03 String常用方法(下)
    182 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 02 String常用方法(上)
    181 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 01 String常用方法简介
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/9735894.html
Copyright © 2011-2022 走看看