webpack5打包生成檔案分析(commonjs和es6模組系統)
阿新 • • 發佈:2021-01-17
目錄
相關配置
- 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
- 函式巢狀,往回執行
- webpack_require(0)
- 函式巢狀,往回執行
- webpack_modules[1]()
- return module.exports(返回獲取count的函式)
- webpack_require(1)
- 函式巢狀,往回執行(輸出count)
- webpack_modules[0]()
- …(下一個事件迴圈,執行定時器)
- webpack_require(0)
- 無定時器,則報錯(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)
參考連結
- https://juejin.cn/post/6844903598480965646
- http://www.qiutianaimeili.com/html/page/2019/12/fnpo81u8ni9.html