Wepack 自身就已经支持模块化,开发者在代码中可以使用各种各样的模块化开发,使用 Webpack 进行打包后会对其进行转换,因此可以直接在浏览器中运行。其中最常见的 CommonJS 和 ESModule。
CommonJS 模块化实现原理:
- 新建
src/js/math/js
文件并编写代码。function sum(num1, num2) { return num1 + num2 } module.exports = {sum}
- 新建
src/index.js
文件并编写代码。const {sum} = require('./js/math.js') console.log(sum(10,20))
- 在
webpack.config.js
配置文件中配置开发模式,使打包后生成的文件不进行压缩丑化,方便阅读代码。module.exports = { mode: 'development', devtool: 'source-map', }
- 运行
webpack
命令进行打包,查看生成的dist/main.js
文件。- Webpack 会定义一个对象用来存放模块的映射。以模块的路径作为 key,以一个函数中作为 value。
- Webpack 会定义一个对象作为加载模块的缓存。
- Webpack 会定义一个函数,当加载模块时都会通过这个函数来加载。
- 判断缓存模块中是否已经加载过该模块,如果有的话,直接返回模块导出的方法。
- 否则的话,会从存放模块映射的对象中获取出模块要导出的变量,将其放入模块缓存对象中,并导出。 - 有一个立即执行函数,真正开始执行代码逻辑,调用加载模块的函数来加载引入的模块。
// 立即执行函数 (() => { // 定义一个对象用来存放模块的映射。以模块的路径作为 key,以一个函数中作为 value。如果有多个模块,将会有多个 key/value var __webpack_modules__ = ({ "./src/js/math.js": ((module) => { function sum(num1, num2) { return num1 + num2 } // 将要导出的变量放到 module.exorts 对象中 module.exports = {sum} }) }); // 定义一个对象作为加载模块的缓存。如果模块被初次加载,就放到这个缓存对象中,之后再读取的话就会更加方便读取 var __webpack_module_cache__ = {}; // 定义一个函数,当加载模块时都会通过这个函数来加载 function __webpack_require__(moduleId) { // 1. 判断缓存模块中是否已经有该模块,如果有的话,直接返回模块导出的方法,就不需要再去加载一次模块中的所有代码 var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } // 2. 如果一次都没有加载过该模块,给 module 变量和模块缓存对象 __webpack_module_cache__[moduleId] 赋值同一个对象 var module = __webpack_module_cache__[moduleId] = {exports: {}}; // 3. 通过执行模块映射对象中指定的模块来获取对应导出的变量 __webpack_modules__[moduleId](module, module.exports, __webpack_require__); // 4. 返回 module.exports return module.exports; } // 立即执行函数。真正开始执行代码逻辑 (() => { // 加载 ./src/js/math.js 模块 const {sum} = __webpack_require__("./src/js/math.js") console.log(sum(10, 20)) })(); })();
ESModule 模块化实现原理:
- 新建
src/js/math/js
文件并编写代码。export function sum(num1, num2) { return num1 + num2 }
- 新建
src/index.js
文件并编写代码。import {sum} from './js/math.js' console.log(sum(10,20))
- 在
webpack.config.js
配置文件中配置开发模式,使打包后生成的文件不进行压缩丑化,方便阅读代码。module.exports = { mode: 'development', devtool: 'source-map', }
- 运行
webpack
命令进行打包,查看生成的dist/main.js
文件。- Webpack 会定义一个对象用来存放模块的映射。以模块的路径作为 key,以一个函数中作为 value。
- Webpack 会定义一个对象作为加载模块的缓存。
- Webpack 会定义一个函数,当加载模块时都会通过这个函数来加载。
- 判断缓存模块中是否已经加载过该模块,如果有的话,直接返回模块导出的方法。
- 否则的话,会从存放模块映射的对象中获取出模块要导出的变量,将其放入模块缓存对象中,并导出。 - 通过三个方法来为加载模块的方法置定义三个属性:添加一个属性来标识是一个 ESModule 模块;判断属性是定义在对象本身上的而不是继承自原型链;为属性设置一层代理,访问 exports 对象的属性其实是在访问 definition 中对应的 get。
- 有一个立即执行函数,真正开始执行代码逻辑,调用加载模块的函数来加载引入的模块。
// 立即执行函数 (() => { "use strict"; // 定义一个对象用来存放模块的映射。以模块的路径作为 key,以一个函数中作为 value。如果有多个模块,将会有多个 key/value var __webpack_modules__ = ({ "./src/js/math.js": ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { // 调用 r 的目的是为了记录该模块是一个 ESModule __webpack_require__.r(__webpack_exports__); // 调用 d 的目的是为了设置一层代理。访问 exports.sum 其实是在访问 definition 中的 get 方法 __webpack_require__.d(__webpack_exports__, { sum: () => (sum) }); function sum(num1, num2) { return num1 + num2 } }) }); // 定义一个对象作为加载模块的缓存。如果模块被初次加载,就放到这个缓存对象中,之后再读取的话就会更加方便读取 var __webpack_module_cache__ = {}; // 定义一个函数,当加载模块时都会通过这个函数来加载 function __webpack_require__(moduleId) { // 1. 判断缓存对象中是否有该模块,如果有的话,直接返回模块导出的方法,就不需要再去加载一次模块中的所有代码 var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } // 2. 如果一次都没有加载过该模块,给 module 变量和模块缓存对象 __webpack_module_cache__[moduleId] 赋值同一个对象 var module = __webpack_module_cache__[moduleId] = {exports: {}}; // 3. 通过执行模块映射对象中指定的模块来获取对应导出的变量 __webpack_modules__[moduleId](module, module.exports, __webpack_require__); // 4. 返回 module.exports return module.exports; } // 立即执行函数。给 __webpack_require__ 函数添加了一个 d 属性,为属性设置一层代理,访问 exports 对象的属性其实是在访问 definition 中对应的 get (() => { __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 属性,判断属性是定义在对象本身上的而不是继承自原型链 (() => { __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) })(); // 立即执行函数。给 __webpack_require__ 函数添加了一个 r 属性,添加 __esModule = true 属性来标识是一个 ESModule 模块 (() => { __webpack_require__.r = (exports) => { if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, {value: 'Module'}); } Object.defineProperty(exports, '__esModule', {value: true}); }; })(); // 立即执行函数。真正开始执行代码逻辑 var __webpack_exports__ = {}; (() => { // 调用 r 的目的是为了记录该模块是一个 ESModule __webpack_require__.r(__webpack_exports__); // 加载 ./src/js/math.js 模块 var _js_math_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/js/math.js"); console.log((0, _js_math_js__WEBPACK_IMPORTED_MODULE_0__.sum)(10, 20)) })(); })();
CommonJS 加载 ESModule 的原理:
在 Webpack 中,可以通过 CommonJS 导入通过 ESModule 导出的内容。
- 新建
src/js/math/js
文件并编写代码。export function sum(num1, num2) { return num1 + num2 }
- 新建
src/index.js
文件并编写代码。const {sum} = require('./js/math.js') console.log(sum(10,20))
- 在
webpack.config.js
配置文件中配置开发模式,使打包后生成的文件不进行压缩丑化,方便阅读代码。module.exports = { mode: 'development', devtool: 'source-map', }
- 运行
webpack
命令进行打包,查看生成的dist/main.js
文件。// 立即执行函数 (function () { // 定义一个对象用来存放模块的映射。以模块的路径作为 key,以一个函数中作为 value。如果有多个模块,将会有多个 key/value var __webpack_modules__ = ({ "./src/js/math.js": (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; // 调用 r 的目的是为了记录该模块是一个 ESModule __webpack_require__.r(__webpack_exports__); // 调用 d 的目的是为了设置一层代理。访问 exports.sum 其实是在访问 definition 中的 get 方法 __webpack_require__.d(__webpack_exports__, { sum: function () { return sum; } }); function sum(num1, num2) { return num1 + num2 } }) }); // 定义一个对象作为加载模块的缓存。如果模块被初次加载,就放到这个缓存对象中,之后再读取的话就会更加方便读取 var __webpack_module_cache__ = {}; // 定义一个函数,当加载模块时都会通过这个函数来加载 function __webpack_require__(moduleId) { // 1. 判断缓存对象中是否有该模块,如果有的话,直接返回模块导出的方法,就不需要再去加载一次模块中的所有代码 var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } // 2. 如果一次都没有加载过该模块,给 module 变量和模块缓存对象 __webpack_module_cache__[moduleId] 赋值同一个对象 var module = __webpack_module_cache__[moduleId] = {exports: {}}; // 3. 通过执行模块映射对象中指定的模块来获取对应导出的变量 __webpack_modules__[moduleId](module, module.exports, __webpack_require__); // 4. 返回 module.exports return module.exports; } // 立即执行函数。给 __webpack_require__ 函数添加了一个 d 属性,为属性设置一层代理,访问 exports 对象的属性其实是在访问 definition 中对应的 get !function () { __webpack_require__.d = function (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 属性,判断属性是定义在对象本身上的而不是继承自原型链 !function () { __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } }(); // 立即执行函数。给 __webpack_require__ 函数添加了一个 r 属性,添加 __esModule = true 属性来标识是一个 ESModule 模块 !function () { __webpack_require__.r = function (exports) { if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; }(); // 立即执行函数。真正开始执行代码逻辑 !function () { // 加载 ./src/js/math.js 模块 const math = __webpack_require__("./src/js/math.js") console.log(math.sum(10, 20)) }(); })();
ESModule 加载 CommonJS 的原理:
在 Webpack 中,可以通过 ESModule 导入通过 CommonJS 导出的内容。
- 新建
src/js/math/js
文件并编写代码。function sum(num1, num2) { return num1 + num2 } module.exports = {sum}
- 新建
src/index.js
文件并编写代码。import {sum} from './js/math.js' console.log(sum(10,20))
- 在
webpack.config.js
配置文件中配置开发模式,使打包后生成的文件不进行压缩丑化,方便阅读代码。module.exports = { mode: 'development', devtool: 'source-map', }
- 运行
webpack
命令进行打包,查看生成的dist/main.js
文件。
// 立即执行函数
(function () {
// 定义一个对象用来存放模块的映射。以模块的路径作为 key,以一个函数中作为 value。如果有多个模块,将会有多个 key/value
var __webpack_modules__ = ({
"./src/js/math.js": (function (module) {
function sum(num1, num2) {
return num1 + num2
}
module.exports = { sum }
})
});
// 定义一个对象作为加载模块的缓存。如果模块被初次加载,就放到这个缓存对象中,之后再读取的话就会更加方便读取
var __webpack_module_cache__ = {};
// 定义一个函数,当加载模块时都会通过这个函数来加载
function __webpack_require__(moduleId) {
// 1. 判断缓存对象中是否有该模块,如果有的话,直接返回模块导出的方法,就不需要再去加载一次模块中的所有代码
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// 2. 如果一次都没有加载过该模块,给 module 变量和模块缓存对象 __webpack_module_cache__[moduleId] 赋值同一个对象
var module = __webpack_module_cache__[moduleId] = {exports: {}};
// 3. 通过执行模块映射对象中指定的模块来获取对应导出的变量
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
// 4. 返回 module.exports
return module.exports;
}
// 立即执行函数。给 __webpack_require__ 函数添加了一个 n 属性,区分是 ESModule 还是 CommonJS 模块,通过不同的函数返回 module 并为函数设置一层代理
!function () {
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function () { return module['default']; } :
function () { return module; };
__webpack_require__.d(getter, { a: getter });
return getter;
};
}();
// 立即执行函数。给 __webpack_require__ 函数添加了一个 d 属性,为属性设置一层代理,访问 exports 对象的属性其实是在访问 definition 中对应的 get
!function () {
__webpack_require__.d = function (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 属性,判断属性是定义在对象本身上的而不是继承自原型链
!function () {
__webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
}();
// 立即执行函数。给 __webpack_require__ 函数添加了一个 r 属性,添加 __esModule = true 属性来标识是一个 ESModule 模块
!function () {
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
}();
// 立即执行函数。真正开始执行代码逻辑
var __webpack_exports__ = {};
!function () {
"use strict";
// 调用 r 的目的是为了记录该模块是一个 ESModule
__webpack_require__.r(__webpack_exports__);
// 加载 ./src/js/math.js 模块
var _js_math_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/js/math.js");
var _js_math_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_js_math_js__WEBPACK_IMPORTED_MODULE_0__);
console.log((0, _js_math_js__WEBPACK_IMPORTED_MODULE_0__.sum)(10, 20))
}();
})();