简述
事实上,ES的import语句中,import default
和import *
并不相同。它们在这种情况下表现相似是React作者选择发布库以及TypeScript(使用esModuleInterop
)或Babel和您的打包工具使用兼容层,使它们“正常工作”的组合结果。根据ES6规范,它可能不应该起作用,但今天我们仍然处于JS模块一团糟的时代,因此像Babel、TypeScript、Webpack等工具尝试规范化其行为。
更多细节:
React不是一个ES6库。如果你看一下源代码,你会在index.js
中看到这个:
const React = require('./src/React');
module.exports = React.default || React;
(注意注释,即使在React源代码中,他们也在努力解决ES6默认导出兼容性问题。)
module.exports =
语法是CommonJS(NodeJS)的语法,浏览器不支持。这就是为什么我们使用像Webpack、Rollup或Parcel这样的打包工具的原因。它们可以理解各种模块语法并生成应在浏览器中正常工作的打包文件。
尽管React不是ES库,但TypeScript和Babel都可以让你像导入ES库一样导入它(使用import
语法而非require()
等),但CJS和ES之间存在差异必须加以解决。其中一个问题是export =
可能会给你一些ES没有规范兼容的方式导入的东西,例如函数或类作为模块。为了解决这些不兼容性,Babel允许你将CJS模块导入为默认导出项,并且可以作为命名空间导入已有一段时间。TypeScript过去没有这样做,但最近添加了一个选项esModuleInterop
。所以现在Babel和TypeScript都可以通过默认或命名空间ES导入相当一致地导入CJS模块。
对于TypeScript还要提到的是,它还取决于库的类型定义如何实际定义。我不会深入讲解,但你可以想象情况,借助转译器和打包工具某个导入在运行时可用,但TypeScript编译时出现错误。
值得一提的另一件事是,如果你查看React的构建代码,你会发现有一个UMD模块版本以及CJS版本。UMD版本包括一些令人头疼的运行时代码,尝试使其在任何模块环境中(包括浏览器)正常工作。主要用于在运行时仅包含React的情况下使用(即你不使用打包工具)。示例。
令人困惑吗?是啊,我也这么认为。
default
,所以应该是:import * as React from 'react';
- Alextsconfig.json
中指定allowSyntheticDefaultImports
。这将允许您使用import React from 'react'
。JavaScript / Babel 在这里“作弊”,即使实际上不存在合成默认导入,也会让您这样做。React
导出的正确语法应该是import * as React from 'react'
。 - John Ruddell