以 React 的使用为例,在 commonjs 的环境下,React 的引用方式是:
const React = require('react');
而在 ES5 的语法中,React 官方使用的引用方式是:
import React from 'react';
(见 create-react-app 中生成的代码)
这就造成了一个问题:require('react')
这样的语法,对应的 import
语法应该怎么写?显然,require
语法无法直接转译成 import
语法:因为根据 import
的语法规则,import React from 'react';
实际是将 default
引入,而 require('react')
的时候,并没有 .default
字段参与。
无论是 Webpack,Babel 还是 TypeScript,在这个问题上都采取了相同的策略,就是在将 import
转译成 require
语句的时候,多套一层:如果 require
的部分有 .default
字段,就使用这个字段;否则的话,就将整体当作是 .default
的值。
在 Webpack 中,使用的是 __webpack_require.n
这个函数:
__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;
};
对于 Babel,使用的是 _interopRequireDefault
这个函数:
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var react = _interopRequireDefault(require('react'));
对于 TypeScript 来说,在 compilerOptions
中增加 esModuleInterop
这个参数,就可以让 tsc 在编译 import
代码的时候进行一层包转转换,使用 __importDefault
确保无论是否是 ES6 module 的输出,都可以被正确的 require:
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const react = __importStar(require("react"));
如果编译结果需要在 Node.js 环境下运行(如进行 Jest 单元测试等),可以考虑上面的配置方案。