博客 / 詳情

返回

webpack簡單文件打包實例

依賴版本

"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 yaofly 頭像 _raymond 頭像 frontoldman 頭像 musicfe 頭像 diyxiaoshitou 頭像 wangji_5d01acdfdd139 頭像 shumin_5bd11c2a4b889 頭像 mosong 頭像 ifnil 頭像 ccVue 頭像 huajianketang 頭像 qiqimachatmk 頭像
13 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.