【闲谈】babel和ts对ES6的import干了什么

·  阅读 2242

前言

前端开发时基本都有babel了,可以 import moment from 'moment';,运行正常。

但是在nodejs的typescript下,有时会报错没有默认导出,要使用import * as moment from 'moment';

此时请检查 tsconfig.jsonesModuleInterop 选项,开启该选项将影响实际编译 并解决此问题 (参考下面babel的处理方式)。另外 allowSyntheticDefaultImports 默认取 esModuleInterop 的值,该选项只影响typescript提示,不影响编译。

因为前端Webpack能够处理commonjs模块,所以下面都编译成commonjs、ES5,且typescript不启用 esModuleInterop 选项

typescript

typescript处理ES6 export

index.ts:

export default 1;
export const a =2;
复制代码

编译成:

"use strict";
exports.__esModule = true;
exports["default"] = 1;
exports.a = 2;
复制代码

就是编译成commonjs规范,直接往exports对象挂属性就行了

exports.__esModule 是普遍规范要求的,这里暂时没啥用

typescript处理ES6 import

index2.ts:

import example, { a } from "./index";
console.log(example, a);
复制代码

编译成

"use strict";
exports.__esModule = true;
var index_1 = require("./index");
console.log(index_1["default"], index_1.a);
复制代码

index_1 是commonjs规范加载回来的对象,这个就是 index.js 文件里面的 exports 对象。

我们在index2.ts的 console.log 中使用的 examplea 变量,编译后会用 index_1["default"]index_1.a 进行替换

babel

babel处理ES6 export

index.js:

export default 1;
复制代码

编译成:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = void 0;
var _default = 1;
exports["default"] = _default;
复制代码

具体代码与ts不同,但是采用的是同一个套路。

babel处理ES6 import

index2.js:

import example from "./index";
console.log(example)
复制代码

编译成:

"use strict";

var _index = _interopRequireDefault(require("./index"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

console.log(_index["default"]);
复制代码

一样的套路,index2.js console.logexample 变量,变成 _index["default"]

babel会有一个“黑魔法”,如果加载的文件是esModule规范(从__esModule属性得知),那么无需处理,_index变量就是require得到的对象。
否则,得到的_index{"default": require("./index")} ,也就是babel把默认导出的对象包了一层放到新对象的default属性去了。

总结

  1. 这里不严谨的总结一下,import 的基本原理就是import 'xxx' === require('xxx').default

  2. babel导入moment.js等commonjs模块时,把他们包装了一下放到新对象的default属性去。而ts不启用esModuleInterop 选项时,没有此特殊操作。

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改