依賴版本
"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 = '入口文件導出內容'
})
});
打包文件分析特點分析
- 打包後的文件就是一個函數自調用,當前函數調用時傳入一個對象。這個對象是一個鍵值對
- 這個鍵名就是當前被加載模塊的文件名與某個目錄的拼接()
- 這個鍵值就是一個函數,和 node.js 裏的模塊加載有一些類似,會將被加載模塊中的內容包裹於一個函數中
- 這個函數在將來某個時間點上會被調用,同時會接收到一定的參數,利用這些參數就可以實現模塊的加載操作
- 針對於上述的代碼就相當於是將 {}(模塊定義) 傳遞給了 modules
__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導出對象,
export default "jack"默認導出時,直接掛載default屬性。而export const age = 18;首先調用r方法標記為一個esModule,然後調用d方法往對象身上掛載一個age屬性,並且給age屬性通過一個getter方法。
EsModule導入CommonJS或者EsModule在於區分導入模塊是否是EsModule,會通過r方法掛載EsModule標記