Stories

Detail Return Return

webpack簡單文件打包實例 - Stories Detail

依賴版本

"webpack": "^4.44.2",
"webpack-cli": "^3.3.12"

一個簡單的文件通過webpack打包

// 導出
console.log('index.js')
module.exports = '導出內容'

// 導入
let log = require('./log.js')
console.log('index.js內容')
console.log(log)

打包後文件

 (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
     //  把index.js導出內容掛載到exports上
     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 = "./src/index.js");
 })

 ({

   "./src/index.js":
     /*! no static exports found */
     (function (module, exports) {
       console.log('index.js內容')
       module.exports = '入口文件導出內容'
     })

 });

打包文件分析特點分析

  1. 打包後的文件就是一個函數自調用,當前函數調用時傳入一個對象。這個對象是一個鍵值對
  2. 這個鍵名就是當前被加載模塊的文件名與某個目錄的拼接()
  3. 這個鍵值就是一個函數,和 node.js 裏的模塊加載有一些類似,會將被加載模塊中的內容包裹於一個函數中
  4. 這個函數在將來某個時間點上會被調用,同時會接收到一定的參數,利用這些參數就可以實現模塊的加載操作
  5. 針對於上述的代碼就相當於是將 {}(模塊定義) 傳遞給了 modules

image.png
__webpack_require__方法是 webpack 當中自定義的,它的核心作用就是返回模塊的 exports。
單文件模塊打包產出文件,會得到一個自調用函數,模塊定義會傳給modules,在文件中會調用__webpack_require__方法,傳入主入口文件id,導出內容會掛載到module.exports上,最後被返回給

  return __webpack_require__(__webpack_require__.s = "./src/index.js");

通過一個CommonJS單步調試,結合打包後代碼可以知道打包後文件一些方法的大概作用

 // 定義對象用於緩存已加載過的模塊
  var installedModules = {};

//__webpack_require__方法是 webpack 自定義的一個加載方法,核心功能就是返回被加載模塊中導出的內容(具體內部是如何實現的,後續再分析)
  function __webpack_require__(moduleId)

// 將模塊定義保存一份,通過 m 屬性掛載到自定義的方法身上
  __webpack_require__.m = modules;

 // o屬性判斷被傳入的對象 obj 身上是否具有指定的屬性*,如果有則返回 true 
  __webpack_require__.o = function (object, property) {
    return Object.prototype.hasOwnProperty.call(object, property);
  };

  // define getter function for harmony exports
  __webpack_require__.d = function (exports, name, getter) {
    // 如果當前 exports 身上不具備 name 屬性,則條件成立,添加成員屬性name
    if (!__webpack_require__.o(exports, name)) {
      Object.defineProperty(exports, name, {
        enumerable: true,
        get: getter
      });
    }

  // define __esModule on exports,給對象加一個標記,判斷是否是esModule
  __webpack_require__.r = function (exports) {
    // 處理 esModule 
    if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
      // Object.prototype.toString.call(exports),添加鍵,值是Module
      Object.defineProperty(exports, Symbol.toStringTag, {
        value: 'Module'
      });
    }
    // 如果條件不成立,我們也直接在 exports 對象的身上添加一個 __esModule 屬性,它的值就是true 
    Object.defineProperty(exports, '__esModule', {
      value: true
    });
  };

  // 調用 t 方法之後,我們會拿到被加載模塊中的內容 value,對於 value 來説我們可能會直接返回,也可能會處理之後再返回
  __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;
  };

CommonJS導入EsModule

// log.js文件下EsMoudle導出
export default "jack"
export const age = 18;

// index.js文件下CommonsJS導入EsModule
let log = require('./log.js')
console.log('index.js內容')
console.log("log", log.default, log.age)

通過 yarn webpack打包
webpack默認支持CommonJS打包,而通過CommonJS規範引入EsMoudle導出對象,
image.png
export default "jack"默認導出時,直接掛載default屬性。而export const age = 18;首先調用r方法標記為一個esModule,然後調用d方法往對象身上掛載一個age屬性,並且給age屬性通過一個getter方法。
image.png

image.png

EsModule導入CommonJS或者EsModule在於區分導入模塊是否是EsModule,會通過r方法掛載EsModule標記

user avatar aqiongbei Avatar leexiaohui1997 Avatar solvep Avatar kongsq Avatar jinl9s27 Avatar infinilabs Avatar coderleo Avatar shanejix Avatar jdcdevloper Avatar haiyong Avatar musicfe Avatar jianer Avatar
Favorites 22 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.