• 深入浅出的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()
      ]
    };
  • 相关阅读:
    CentOS 7修改用户密码
    Java EE(Web)大方向
    【Spring学习随笔】4. Spring AOP
    Git从本地上传项目到Github
    Vue及Vue-Cli的环境搭建(Windows)
    【Spring学习随笔】3. Spring Bean
    SSM框架随笔
    IDEA中Spring配置错误:class path resource [.xml] cannot be opened because it does not exist
    Jsp技术
    【Spring学习随笔】2. Spring IoC
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/9735894.html
Copyright © 2020-2023  润新知