1. 程式人生 > 其它 >webpack5打包生成檔案分析(commonjs和es6模組系統)

webpack5打包生成檔案分析(commonjs和es6模組系統)

技術標籤:前端工程化webpack前端模組系統

目錄

相關配置

  • webpack5
// webpack.config.js
module.exports = {
  mode: 'none'
}
// index.js
import str from "./main.js";
console.log(str);
// main.js
export default "hello leo~";
  • 生成檔案(去掉了註釋)
(() => {
  "use strict";
  var __webpack_modules__ = ([
    ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
      __webpack_require__.r(__webpack_exports__);
      var _main_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
      console.log(_main_js__WEBPACK_IMPORTED_MODULE_0__.
default); }), ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => __WEBPACK_DEFAULT_EXPORT__ }); const __WEBPACK_DEFAULT_EXPORT__ =
("hello leo~"); }) ]); var __webpack_module_cache__ = {}; function __webpack_require__(moduleId) { if (__webpack_module_cache__[moduleId]) { return __webpack_module_cache__[moduleId].exports; } var module = __webpack_module_cache__[moduleId] = { exports: {} }; __webpack_modules__[moduleId](module, module.exports, __webpack_require__); console.log(module.exports, moduleId) // 測試程式碼 return module.exports; } (() => { __webpack_require__.d = (exports, definition) => { for (var key in definition) { if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } } }; })(); (() => { __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop) })(); (() => { __webpack_require__.r = (exports) => { if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; })(); __webpack_require__(0); })();

生成檔案分析

  • 使用es5 實現import和export
  • webpack_modules ,儲存所有模組的陣列
  • webpack_require,根據模組ID,遞迴呼叫模組,返回匯出物件(module.exports)
  • webpack_module_cache,根據模組ID,快取模組資料
  • webpack_require.d,根據匯入模組,設定exports成員
  • webpack_require.o,判斷自有屬性
  • webpack_require.r,初始化匯出模組物件
  • webpack_require(0),執行 entry 中程式碼

es6模組和commonjs模組輸出值

  • esModule輸出值的引用(函式閉包)
// index.js
import { count, add } from './main.js'

console.log(count)  //0
add();
console.log(count)  //1

// main.js
export let count = 0;//輸出的是值的引用,指向同一塊記憶體
export const add = () => {
  count++;//此時引用指向的記憶體值發生改變
}

// index模組
/* 0 */
    /***/
    ((__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{

        __webpack_require__.r(__webpack_exports__);
        /* harmony import */
        var _main_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
        // index.js

        console.log(_main_js__WEBPACK_IMPORTED_MODULE_0__)
        console.log(_main_js__WEBPACK_IMPORTED_MODULE_0__.count)//0
        ;
        (0,
        _main_js__WEBPACK_IMPORTED_MODULE_0__.add)();
        console.log(_main_js__WEBPACK_IMPORTED_MODULE_0__.count)
        //1

        /***/
    }
    )
// main模組
 /* 1 */
    /***/
    ((__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{

        __webpack_require__.r(__webpack_exports__);
        /* harmony export */
        __webpack_require__.d(__webpack_exports__, {
            /* harmony export */
            "count": ()=>/* binding */
            count,
            /* harmony export */
            "add": ()=>/* binding */
            add /* harmony export */
        });
        // main.js
        let count = 0;
        //輸出的是值的引用,指向同一塊記憶體
        const add = ()=>{
            count++;
            //此時引用指向的記憶體值發生改變
        }

        /***/
    }
    )/******/

在這裡插入圖片描述

  • commonJs輸出的是值的淺拷貝
    • commonjs模組 無 webpack_require 形參
    • 直接在 exports 地址上新增屬性
    • 直接賦值(基本型別無引用,物件淺拷貝)
// main.js
let count = 0
exports.count = count; // 輸出值的拷貝
exports.add = () => {
  //這裡改變count值,並不會將module.exports物件的count屬性值改變
  count++;
}

// index.js
const { count, add } = require('./main.js')

console.log(count) //0
add();
console.log(count)  //0

// 輸出模組
var __webpack_modules__ = ([/* 0 */
    , /* 1 */
    /***/
    ((__unused_webpack_module,exports)=>{

        // main.js
        let count = 0
        exports.count = count;
        // 輸出值的拷貝
        exports.add = ()=>{
            //這裡改變count值,並不會將module.exports物件的count屬性值改變
            count++;
        }

        /***/
    }
    )/******/
    ]);
(()=>{
        // index.js
        const {count, add} = __webpack_require__(1)

        console.log(count)
        //0
        add();
        console.log(count)
        //0
    }
    )();
  • 設定定時器
// main.js
let count = { a: 1 }
exports.count = count; // 輸出值的拷貝

setTimeout(() => {
  //改變 foo 的記憶體指向
  exports.count = 'haha';
}, 1000)

// index.js
const { count, add } = require('./main.js')

console.log(count) //0
setTimeout(() => {
  console.log(count)
}, 2000)

// 輸出
 (()=>{
        // index.js
        const {count, add} = __webpack_require__(1)

        console.log(count)
        //0
        setTimeout(()=>{
            console.log(count)
        }
        , 2000)
    }
    )();

es6模組和commonjs模組動態載入

  • 動態import時,編譯報錯
Module parse failed: 'import' and 'export' may only appear at the top level (4:2)
  • 使用 import() 函式
// index.js
(async () => {
  if (true) {
    // const { count } = require('./main.js')
    const count = await import('./main')
    console.log(count.default) 
  }
})()
// 輸出
 // index.js
    (async()=>{
        if (true) {
            // const { count } = require('./main.js')
            const count = await __webpack_require__.e(/* import() */
            1).then(__webpack_require__.t.bind(__webpack_require__, 1, 19))
            console.log(count.default)
            
        }
    }
    )()

在這裡插入圖片描述

  • 使用 require
// index.js
if (true) {
  const { count } = require('./main.js')
  // import { count } from './main'
  // const count = await import('./main')
  console.log(count)
}

//輸出
/******/
    var __webpack_modules__ = ([/* 0 */
    , /* 1 */
    /***/
    ((__unused_webpack_module,exports)=>{

        // main.js
        let count = 1
        exports.count = count;
        // 輸出值的拷貝

        /***/
    }
    )/******/
    ]);
 (()=>{
        // index.js
        if (true) {
            const {count} = __webpack_require__(1)
            // import { count } from './main'
            // const count = await import('./main')
            console.log(count)
        }
    }
    )();

es6模組和commonjs模組迴圈引用

// index.js
import { count } from './b.js'
console.log(count);
export let message = 'hello'

// b.js
import { message } from './index.js'
export let count = 5;
setTimeout(() => {
  console.log(message);
}, 0);

// 輸出模組
 var __webpack_modules__ = ([/* 0 */
    /***/
    ((__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{

        __webpack_require__.r(__webpack_exports__);
        /* harmony export */
        __webpack_require__.d(__webpack_exports__, {
            /* harmony export */
            "message": ()=>/* binding */
            message /* harmony export */
        });
        /* harmony import */
        var _b_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
        // index.js

        console.log(_b_js__WEBPACK_IMPORTED_MODULE_0__.count);
        let message = 'hello'

        /***/
    }
    ), /* 1 */
    /***/
    ((__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{

        __webpack_require__.r(__webpack_exports__);
        /* harmony export */
        __webpack_require__.d(__webpack_exports__, {
            /* harmony export */
            "count": ()=>/* binding */
            count /* harmony export */
        });
        /* harmony import */
        var _index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
        // a.js

        let count = 5;
        setTimeout(()=>{
            console.log(_index_js__WEBPACK_IMPORTED_MODULE_0__.message);
        }
        , 0);

        /***/
    }
    )/******/
    ]);
  • 斷點除錯,函式執行順序
    • webpack_require(0)
      • webpack_modules[0]()
        • webpack_require(1)
          • webpack_modules[1]()
            • webpack_require(0)
              • return webpack_module_cache[moduleId].exports
            • 函式巢狀,往回執行
          • 函式巢狀,往回執行
        • return module.exports(返回獲取count的函式)
      • 函式巢狀,往回執行(輸出count)
    • …(下一個事件迴圈,執行定時器)
  • 無定時器,則報錯(let 宣告無變數提升效果,取值時未賦值)

在這裡插入圖片描述

// 類似報錯
(() => {
  console.log(age);
  let age = 21;//ES6中沒有變數提升
})()
  • commonjs demo
/*c.js: entry*/
var count = require('./d.js').count;
console.log(count);
exports.message = 'hello';
/*d.js*/
var message = require('./c.js').message;
exports.count = 5;
console.log(message);


// 輸出模組
var __webpack_modules__ = ([/* 0 */
    /***/
    ((__unused_webpack_module,exports,__webpack_require__)=>{

        /*c.js*/
        var count = __webpack_require__(1).count;
        console.log(count);
        exports.message = 'hello';

        /***/
    }
    ), /* 1 */
    /***/
    ((__unused_webpack_module,exports,__webpack_require__)=>{

        /*d.js*/
        var message = __webpack_require__(0).message;
        exports.count = 5;
        console.log(message);

        /***/
    }
    )/******/
    ]);
  • 函式棧
    -> 模組1
    -> 模組2(取模組1快取,輸出 undefined,模組2 exports 賦值)
    -> 模組1 (輸出 5)
    在這裡插入圖片描述

參考連結

demo

https://github.com/baixc1/csdn/tree/master/note/note16