CommonJs模块化实现原理ES Module模块化原理

CommonJs模块化实现原理

首先看一个案例
初始化项目

npm init
npm i webpack -D

目录结构如下

在这里插入图片描述
webpack.config.js

const path = require("path");
module.exports = {mode: "development",entry: "./src/index.js",output: {path: path.resolve(__dirname, "dist"),filename: "[name].js",},devtool: "source-map"
};

src/index.js

const b = require("./b");
const a = require("./a");
console.log(a, b)

src/a.js

let a = "这是a"
module.exports = a;

src/b.js

let b = "这是b"
module.exports = b;

build.js

const { webpack } = require("webpack");
const webpackOptions = require("./webpack.config.js");const compiler = webpack(webpackOptions);compiler.run((err, stats) => {console.log(err)
});

进行node ./build.js后查看dist文件下

(() => { var __webpack_modules__ = ({"./src/a.js": ((module) => {let a = "这是a"module.exports = a;}),"./src/b.js":((module) => {let b = '这是b'module.exports = b;})});// The module cachevar __webpack_module_cache__ = {};// The require functionfunction __webpack_require__(moduleId) {// Check if module is in cachevar cachedModule = __webpack_module_cache__[moduleId];if (cachedModule !== undefined) {return cachedModule.exports;}// Create a new module (and put it into the cache)var module = __webpack_module_cache__[moduleId] = {// no module.id needed// no module.loaded neededexports: {}};// Execute the module function__webpack_modules__[moduleId](module, module.exports, __webpack_require__);// Return the exports of the modulereturn module.exports;}var __webpack_exports__ = {};(() => {const b = __webpack_require__("./src/b.js");const a = __webpack_require__("./src/a.js");console.log(a, b);})();})()
;
//# sourceMappingURL=main.js.map

分析一下打包产物

首先看下 webpack_modules,我们在src/index.js中引入了a.js、b.js, webpack会把’src/a.js’、‘src/b.js’作为modules的key值,该模块内容作为modules的value值;

 var __webpack_modules__ = ({"./src/a.js": ((module) => {let a = "这是a"module.exports = a;}),"./src/b.js":((module) => {let b = '这是b'module.exports = b;})});

定义 __webpack_require__函数

	var __webpack_module_cache__ = {};function __webpack_require__(moduleId) {// 判断一下缓存中有没有当前modulevar cachedModule = __webpack_module_cache__[moduleId];if (cachedModule !== undefined) {// 缓存中有的话走缓存,返回cachedModule.exportsreturn cachedModule.exports;}// 缓存中没有就重新创建一个moudle,设置export对象,并放入缓存var module = __webpack_module_cache__[moduleId] = {exports: {}};// 执行模块代码, 传入当前module,根据需要传入module.exports, __webpack_require__,module.exports会在模块中赋值__webpack_modules__[moduleId](module, module.exports, __webpack_require__);// 返回module.exportsreturn module.exports;}

执行入口函数,为防止命名污染,封装成立即执行函数。

 (() => {const b = __webpack_require__("./src/b.js");const a = __webpack_require__("./src/a.js");console.log(a, b);})();

ES Module模块化原理

src/index.js

import a from './a'
import {b} from './b'
console.log(a, b);

src/a.js

const a = "这是a"
export default a

src/b.js

export const b = '这是b'

node ./build.js 之后main.js如下:

 (() => { "use strict";var __webpack_modules__ = ({"./src/a.js":((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {__webpack_require__.r(__webpack_exports__);__webpack_require__.d(__webpack_exports__, {"default": () => (__WEBPACK_DEFAULT_EXPORT__)});const a = "这是a"const __WEBPACK_DEFAULT_EXPORT__ = (a);}),"./src/b.js":((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {__webpack_require__.r(__webpack_exports__);__webpack_require__.d(__webpack_exports__, {b: () => (b)});const b = '这是b'})});var __webpack_module_cache__ = {};function __webpack_require__(moduleId) {var cachedModule = __webpack_module_cache__[moduleId];if (cachedModule !== undefined) {return cachedModule.exports;}var module = __webpack_module_cache__[moduleId] = {exports: {}};__webpack_modules__[moduleId](module, module.exports, __webpack_require__);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 });};})();var __webpack_exports__ = {};(() => {__webpack_require__.r(__webpack_exports__);var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");var _b__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/b.js");console.log(_a__WEBPACK_IMPORTED_MODULE_0__["default"], _b__WEBPACK_IMPORTED_MODULE_1__.b);})();})()
;
//# sourceMappingURL=main.js.map

如果是通过export default 方式导出的,那就在 exports 对象加一个 default 属性

var __webpack_modules__ = ({"./src/a.js":((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {// 在 ESM 模式下声明 ESM 模块标识__webpack_require__.r(__webpack_exports__);// 将模块导出的内容附加的模块对象上,如果是通过export default导出,给exports的对象加default属性__webpack_require__.d(__webpack_exports__, {"default": () => (__WEBPACK_DEFAULT_EXPORT__)});const a = "这是a"const __WEBPACK_DEFAULT_EXPORT__ = (a);}),"./src/b.js":((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {__webpack_require__.r(__webpack_exports__);__webpack_require__.d(__webpack_exports__, {b: () => (b)});const b = '这是b'})});

通过__webpack_require__.r把模块标识为 ES Module
了解Symbol.toStringTag

(() => {__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__.d对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))})();

ES Module加载CommonJS实现原理
src/index.js

import b from './b'
console.log(b);

src/b.js

let b = '这是b'
module.exports = b;

node ./build.js之后

 (() => { var __webpack_modules__ = ({"./src/b.js": ((module) => {let b = '这是b'module.exports = b;})});var __webpack_module_cache__ = {};function __webpack_require__(moduleId) {var cachedModule = __webpack_module_cache__[moduleId];if (cachedModule !== undefined) {return cachedModule.exports;}var module = __webpack_module_cache__[moduleId] = {exports: {}};__webpack_modules__[moduleId](module, module.exports, __webpack_require__);return module.exports;}(() => {__webpack_require__.n = (module) => {var getter = module && module.__esModule ?() => (module['default']) :() => (module);__webpack_require__.d(getter, { a: getter });return getter;};})();(() => {__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 });};})();var __webpack_exports__ = {};(() => {"use strict";__webpack_require__.r(__webpack_exports__);var _b__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/b.js");var _b__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_b__WEBPACK_IMPORTED_MODULE_0__);console.log((_b__WEBPACK_IMPORTED_MODULE_0___default()));})();})()
;
//# sourceMappingURL=main.js.map

由此可以看出加了这一个步骤:
通过__webpack_require__.n判断模块是否是esModule返回module

	(() => {__webpack_require__.n = (module) => {var getter = module && module.__esModule ?() => (module['default']) :() => (module);__webpack_require__.d(getter, { a: getter });return getter;};})();

CommonJS加载ES Module的实现原理

src/index.js

const b = require('./b.js')
console.log(b);

src/b.js

let b = '这是b'
export default b;

node ./build.js之后

 (() => {var __webpack_modules__ = ({"./src/b.js": ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {"use strict";__webpack_require__.r(__webpack_exports__);__webpack_require__.d(__webpack_exports__, {"default": () => (__WEBPACK_DEFAULT_EXPORT__)});let b = '这是b'const __WEBPACK_DEFAULT_EXPORT__ = (b);})});var __webpack_module_cache__ = {};function __webpack_require__(moduleId) {var cachedModule = __webpack_module_cache__[moduleId];if (cachedModule !== undefined) {return cachedModule.exports;}var module = __webpack_module_cache__[moduleId] = {exports: {}};__webpack_modules__[moduleId](module, module.exports, __webpack_require__);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 });};})();var __webpack_exports__ = {};(() => {const b = __webpack_require__(/*! ./b.js */ "./src/b.js")console.log(b);})();})()
;
//# sourceMappingURL=main.js.map

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/217535.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2019年第八届数学建模国际赛小美赛C题预测通过拥堵路段所需的时间解题全过程文档及程序

2019年第八届数学建模国际赛小美赛 C题 预测通过拥堵路段所需的时间 原题再现: 在导航软件中,行程时间的估计往往是一个重要的功能。现有的导航软件往往通过出租车或安装了该软件的车辆获取实时GPS数据来确定当前的路况。在交通拥堵严重的情况下&#…

安装LLaMA-Factory微调chatglm3,修改自我认知

安装git clone https://github.com/hiyouga/LLaMA-Factory.git conda create -n llama_factory python3.10 conda activate llama_factory cd LLaMA-Factory pip install -r requirements.txt 之后运行 单卡训练, CUDA_VISIBLE_DEVICES0 python src/train_web.py…

过拟合与欠拟合

一、模型选择 1、问题导入 2、训练误差与泛化误差 3、验证数据集和测试数据集 4、K-折交叉验证 一般在没有足够多数据时使用。 二、过拟合与欠拟合 1、过拟合 过拟合的定义: 当学习器把训练样本学的“太好”了的时候,很可能已经把训练样本自身的一些特…

Navicat16 无限试用 亲测有效

Navicat16 无限试用 亲测有效 亲测有效!!! 吐槽下,有的用不了,有的是图片,更甚者还有收费的,6的一批 粘贴下面的代码,保存到桌面,命名为 trial-navicat16.bat echo off…

探索GameFi:区块链与游戏的未来融合

在过去的几年里,区块链技术逐渐渗透到各个领域,为不同行业带来了前所未有的变革。其中,游戏行业成为了一个引人注目的焦点,而这种结合被称为GameFi,即游戏金融。GameFi不仅仅是一个概念,更是一场区块链和游…

宏景eHR SQL 注入漏洞复现(CVE-2023-6655)

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR 中发现了一种被分类为关键的漏洞,该漏洞影响了Login Interface组件中/w_selfservice/oauthservlet/%2e../.%2e/genera…

关于“Python”的核心知识点整理大全19

目录 ​编辑 8.6.4 使用 as 给模块指定别名 8.6.5 导入模块中的所有函数 8.7 函数编写指南 8.8 小结 第9章 类 9.1 创建和使用类 9.1.1 创建 Dog 类 dog.py 1. 方法__init__() 2. 在Python 2.7中创建类 9.1.2 根据类创建实例 1. 访问属性 2. 调用方法 3. 创建多…

到底什么是DevOps

DevOps不是一组工具,也不是一个特定的岗位。在我看来DevOps更像是一种软件开发文化,一种实现快速交付能力的手段。 DevOps 强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的…

宠物自助洗护小程序系统

提供给宠物的自助洗澡机, 集恒温清洗、浴液 护毛、吹干、消毒于一体,宠物主人只需用微信小程序源码,即可一键开启洗宠流程。 主要功能: 在线预约 在线支付 洗护记录 会员系统 宠物管理 设备管理 多商户加盟

大数据技术10:Flink从入门到精通

导语:前期入门Flink时,可以直接编写通过idea编写Flink程序,然后直接运行main方法,无需搭建环境。我碰到许多初次接触Flink的同学,被各种环境搭建、提交作业、复杂概念给劝退了。前期最好的入门方式就是直接上手写代码&…

win10 + vs2017 + cmake3.17编译OSG-3.4.1

1. 下载文件 主要用到4个文件 1)OSG-3.4.1源码2)OSG第三方依赖库3)OSG示例数据4)cmake-3.17 我已经准备好了,大家可以自行下载。下载路径: 链接:https://pan.baidu.com/s/1E3YESh0T9KPlJJe2…

Android--Jetpack--Navigation详解

须知少日拏云志,曾许人间第一流 一,定义 Navigation 翻译成中文就是导航的意思。它是谷歌推出的Jetpack的一员,其目的主要就是来管理页面的切换和导航。 Activity 嵌套多个 Fragment 的 UI 架构模式已经非常普遍,但是对 Fragmen…

机器人制作开源方案 | 智能助老机器人

作者:刘颖、王浩宇、党玉娟 单位:北京科技大学 指导老师:刘新洋、栗琳 1. 项目背景 1.1 行业背景 随着越来越多的服务机器人进入家庭,应用场景呈现多元化和专业化,机器人产业生态体系正在不断完善,服务…

【MySQL】MySQL库的增删查改

文章目录 1.库的操作1.1创建数据库1.2创建数据库案例 2.字符集和校验规则2.1查看系统默认字符集以及校验规则2.2查看数据库支持的字符集2.3查看数据库支持的字符集校验规则2.4校验规则对数据库的影响 3.操纵数据库3.1查看数据库3.2显示创建语句3.3修改数据库3.4数据库删除3.5备…

2023年医疗器械行业分析(京东医疗器械运营数据分析):10月销额增长53%

随着我国整体实力的增强、国民生活水平的提高、人口老龄化、医疗保障体系不断完善等因素的驱动,我国的医疗器械市场增长迅速。 根据鲸参谋电商数据分析平台的相关数据显示,今年10月份,京东平台上医疗器械市场的销量将近1200万,环比…

1+X大数据平台运维职业技能等级证书中级

该部分是选择题部分,实操题在主页的另一篇文章 考试名称:“1X”大数据平台运维职业技能等级证书(中级) 1X 大数据平台运维中级测试题一、单选题 以下哪种情况容易引发 HDFS 负载不均问题?( C&#xff09…

windows禁用系统更新

1.在winr运行框中输入services.msc,打开windows服务窗口。 services.msc 2.在服务窗口中,我们找到Windows update选项,如下图所示: 3.双击windows update服务,我们把启动类型改为禁用,如下图所示&#xff…

AI浪潮下,大模型如何在音视频领域运用与实践?

视频云大模型算法「方法论」。 刘国栋|演讲者 在AI技术发展如火如荼的当下,大模型的运用与实践在各行各业以千姿百态的形式展开。音视频技术在多场景、多行业的应用中,对于智能化和效果性能的体验优化有较为极致的要求。如何运用好人工智能提…

STM32--中断使用(超详细!)

写在前面:前面的学习中,我们接触了STM32的第一个外设GPIO,这也是最常用的一个外设;而除了GPIO外,中断也是一个十分重要且常用的外设;只有掌握了中断,再处理程序时才能掌握好解决实际问题的逻辑思…

Arris VAP2500 list_mac_address未授权RCE漏洞复现

0x01 产品简介 Arris VAP2500是美国Arris集团公司的一款无线接入器产品。 0x02 漏洞概述 Arris VAP2500 list_mac_address接口处命令执行漏洞,未授权的攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限,进而控制整个web服务器。 0x03 复现环境 FOFA…