浅析babel产出
(function(modules) {
// 缓存对象
var installedModules = {};
// require方法
function __webpack_require__(moduleId) {
// 是否命中缓存
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 新建 + 缓存
var module = (installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
});
// 执行module方法
modules[moduleId].call(
module.exports,
module,
module.exports,
__webpack_require__
);
// 标志是否已加载模块,之后缓存里会走
module.l = true;
return module.exports;
}
// expose the modules object (__webpack_modules__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// 设置commonjs导出的对象上的a的值
__webpack_require__.d = function(exports, name, getter) {
if (!__webpack_require__._hasOwnProperty(exports, name)) {
// 利用 getter 可以通过a获取到module的值
Object.defineProperty(exports, name, {
enumerable: true,
get: getter
});
}
};
// 定义 __esModule 标志
__webpack_require__.r = function(exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: 'Module'
});
}
Object.defineProperty(exports, '__esModule', {value: true});
};
// 适配commonjs规范
// 导出的为 require.a => 执行 getter函数 获得导出的内容
__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__._hasOwnProperty = function(object, property) {
return Object.prototype.hasOwnProperty.call(object, property);
};
})({})
概述下上面打包后的代码,是一个立即执行函数,接受的参数是一个对象,对象的key为引入的模块路径,对应的value为导出的内容,不过babel会根据ejs or cjs来进行不同的适配导出。
iife函数内为:
- installedModules 闭包环境缓存模块对象
- webpack_require 变种的require方法
- webpack_require.d 适配commonjs的转换方法
- webpack_require.r 给babel转换的es6模块增加标志,也就是通过该方法来设置区分ejs 和 cjs的标志
- _webpack_require.n 根据 __esModule 导出
举例说明:
我们有以下几个文件,内容都很简单。
// es6.js
export default {
type: 'esjs'
}
// commonjs.js
module.exports = {
type: 'commonjs'
}
// index.js
import es6 from './es6';
import conmon from './commonjs';
console.log(require('./es6'));
console.log(es6, 'import来的');
console.log(require('./commonjs'));
console.log(conmon, 'import来的');
通过webpack打包后的输出内容我们只取上面iife函数的参数部分,并去掉eval来提升可读性。
// bundle.js
(function(modules){
// ******
// 巴拉巴拉
// ******
// Load entry module and return exports
return __webpack_require__((__webpack_require__.s = './index.js'));
})({
'./commonjs.js': function(module, exports) {
module.exports = {type: 'commonjs'};
},
'./es6.js': function(module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
// 相当于 module.exports.default,这就是为什么我们require的时候,需要加上 .default
__webpack_exports__['default'] = {
type: 'esjs'
};
},
'./index.js': function(module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
var es6FromImport = __webpack_require__('./es6.js');
var commonjsFromImport = __webpack_require__(
'./commonjs.js'
);
var commonjsFromImport_default = __webpack_require__.n(
commonjsFromImport
);
console.log(__webpack_require__('./es6.js'));
console.log(es6FromImport['default'], 'import来的');
console.log(__webpack_require__('./commonjs.js'));
console.log(
commonjsFromImport_default.a,
'import来的'
);
}
})
一点点分析,从入口开始 => webpack_require('./index.js')
首先会查看是否命中缓存,如果命中,那理所当然直接返回,否则进行新建 + 缓存的操作,边边角角直接略过,咱们看下面这个方法:
// 新建
var module = (installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
});
// 赋值
modules[moduleId].call(
module.exports,
module,
module.exports,
__webpack_require__
);
// 导出
return module.exports;
首先新建,并创建默认的导出对象,这也就说明了为什么文件没有导出,默认是{}的问题,然后,利用call传递函数执行上下文环境,并传入module, module.exports, webpack_require 参数,最后return了module中的exports的值。
来看关键的赋值这一步。
针对es6js,因为你是export default,所以babel会增加一个__esModule变量,进行ejs的标识,因为我们导出的时候,会根据ejs规范,导出得对象赋值到default上,如下
// 赋值 __esModule
__webpack_require__.r(__webpack_exports__);
__webpack_exports__['default'] = {
type: 'esjs'
};
当我们使用ejs规范import的时候,babel会进行default的读取,所以我们可以直接获取到我们想要的值,然后如果你使用require的话,babel会按照commonjs直接进行读取,所以会导致我们需要 .default 才能拿到我们真正想要的值,结果如下
针对cjs,由于使用cjs规范,所以我们的导出是不涉及default的,即
module.exports = { type: 'commonjs' }
其实我们直接导出即可,因为 webpack_require 的返回值就是 module.exports。
不过打包后的代码用 webpack_require.n 对commonjs的导出做了处理,判断是否为 es6 规范的导出,如果是那么导出default,不是直接导出module.exports,然后使用 getter 设置返回函数的a属性,获取a属性即返回cjs module的导出,猜测这是对es6 import的统一处理。
// require
var commonjsFromImport = __webpack_require__('./commonjs.js');
// 设置getter
var commonjsFromImport_default = __webpack_require__.n(commonjsFromImport);
console.log(commonjsFromImport_default.a, 'import来的');
结果如下:
简单总结
require 对 ejs 规范的导出不是很友好,换句话说,考虑的很单一,所以会有default的问题
import 适配的 ejs 和 cjs,会根据 __esModule 进行导出的判断,返回使用者真正想要的
不过进步一认证,发现如果是ejs的导出,会直接导出__webpack_export__['default'],也就是 module.export.defualt,看起来不需要处理 __esModule 的请求,暂时还不清楚到底是怎么回事。有缘窃听下回分解吧。
具体babel是怎么解析的,暂时不涉及,只分析结果,得出一点点结论。
小提示
类似这种的代码 (0, foo.bar)() 相当于 foo.bar.call(winodw|global|this) 改变执行时的上下文环境
浅析babel产出的更多相关文章
- ES6学习(1)——如何通过babel将ES6转化成ES5
使用babel编译ES6 babel是一个工具,可以通过多个平台,让js文件从ES6转化成ES5,从而支持一些浏览器并未支持的语法. Insall babel $ sudo npm install b ...
- 前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数
一.AMD和CMD规范(了解) 1.1传统的前端开发多个js文件的关系 yuan.js中定义了一个函数 function mianji(r){ return 3.14 * r * r } main.j ...
- vue2组件懒加载浅析
vue2组件懒加载浅析 一. 什么是懒加载 懒加载也叫延迟加载,即在需要的时候进行加载,随用随载. 二.为什么需要懒加载 在单页应用中,如果没有应用懒加载,运用webpack打包后的文件将会异常的大, ...
- ffmpeg转码步骤源码实现的一点点浅析
ffmpeg转码实现的一点点浅析 ffmpeg转码过程对解码的处理封装在process_input()中(process_input()->decode_video()->decode() ...
- AnalyticDB实现和特点浅析
目录 AnalyticDB介绍与背景 AnalyticDB详细解析 架构设计 数据分区 读写分离和读写流程 其他特性介绍 混合(列-行)存储引擎 索引 小结 本篇主要是根据AnalyticDB的论文, ...
- SQL Server on Linux 理由浅析
SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...
- 【深入浅出jQuery】源码浅析--整体架构
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 高性能IO模型浅析
高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking ...
- netty5 HTTP协议栈浅析与实践
一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...
随机推荐
- Pandas 转换连接
# 导入相关库 import numpy as np import pandas as pd 拼接 有两个 DataFrame,都存储了用户的一些信息,现在要拼接起来,组成一个 DataFrame. ...
- jdbc 加载数据库驱动如何破坏双亲委托模式
导读 通过jdbc链接数据库,是每个学习Java web 方向的人必然一开始会写的代码,虽然现在各路框架都帮大家封装好了jdbc,但是研究一下jdbc链接的套路还是很意义 术语以及相 ...
- beacon帧字段结构最全总结(一)——beacon基本结构
一.beacon帧主要结构 二.MAC header 1.Version:版本号,目前为止802.11只有一个版本,所以协议编号为0 2.Type:定义802.11帧类型,802.11帧分为管理帧( ...
- node.js评论列表和添加购物车数据库表创建
2.1:评论列表--发表评论 用户点击新闻列表某一条新闻,看到新闻详细发表评论 -用户输入评论内容 -发表评论 [将用户评论内容保存数据库 xz_comment] 2.2:评论列表--发表评论-开发评 ...
- Jquery EasyUI 中ValidateBox验证框使用讲解
来源素文宅博客:http://blog.yoodb.com/ Validatebox(验证框)的设计目的是为了验证输入的表单字段是否有效.如果用户输入了无效的值,它将会更改输入框的背景颜色,并且显示警 ...
- Hbase简介以及简单的入门操作
Hbase是一个分布式的.面向列的开源数据库,可实时的读写.随机访问超大规模的数据集. Hbase主要分为两种模型: 逻辑模型和物理模型 1. 逻辑模型 Hbase的名字的来源是Hadoop data ...
- vue 实现单选/多选效果
转:https://blog.csdn.net/Number7421/article/details/81002729 不过我以前都写过这三种方法了,很pang额,怕之后忘记了,偷个懒拿别人的,以免以 ...
- go-micro+php+consul简单的微服实现
首先我们用go-micro构建一个服务.(关于go-micro的使用可以参照官方实例或者文档) //新建一个微服务 micro new --type "srv" user-srv ...
- 在 ASP.NET Core 项目中使用 MediatR 实现中介者模式
一.前言 最近有在看 DDD 的相关资料以及微软的 eShopOnContainers 这个项目中基于 DDD 的架构设计,在 Ordering 这个示例服务中,可以看到各层之间的代码调用与我们之前 ...
- Salesforce学习之路(十一)Aura组件属性<aura:attribute />
1. <aura:attribute />语法 Aura组件属性类似与Apex中类的成员变量(或者说Java中类的成员变量).他们是组件在特定的实例上设置的类型化字段,可以使用表达式语法从 ...