我注意到React
可以这样导入:
import * as React from 'react';
...或者像这样:
import React from 'react';
第一个导入react
模块中的所有内容(请参阅:Import an entire module's contents)
第二个仅导入default
模块导出(请参阅:Importing defaults)
这两种方法似乎是不同的,而且根本不兼容。
为什么它们都起作用?
请参考源代码并解释该机制...我有兴趣了解其工作原理。
更新
这不是What is the difference between import * as react from 'react' vs import react from 'react'
的副本。使用一般的ES6模块信息回答了该问题。
我正在询问使react
模块像这样工作的机制。它似乎与“ hacky”导出机制in the source here有关,但目前尚不清楚如何将 entire 模块导入和仅将 default 导出到{{ 1}},并同时使用这两种方法来编译JSX等。
答案 0 :(得分:4)
独立的ES导入语句import default
和import *
并不相同,在这种情况下它们的行为相同是React作者选择发布库和兼容性层的方式的结合。 TypeScript(使用esModuleInterop
)或Babel和您的捆绑软件以使其“正常工作”。它可能不应该根据ES6规范工作,但是今天我们仍然在一个JS模块混乱的时代工作,因此Babel,TypeScript,Webpack等工具试图规范行为。
React不是ES6库。如果您查看the source code,则会在index.js
中看到以下内容:
const React = require('./src/React');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = React.default || React;
(请注意注释,即使在React源代码中,它们也难以与ES6默认导出兼容性兼容。)
module.exports =
语法为CommonJS(NodeJS)。浏览器不会理解这一点。这就是为什么我们使用Webpack,Rollup或Parcel之类的捆绑器的原因。他们了解各种模块语法,并生成应在浏览器中使用的捆绑软件。
但是,尽管React不是ES库,但TypeScript和Babel都可以像导入它一样(使用import
语法,而不是require()
等)来导入它,但是两者之间存在差异必须解决的CJS和ES。其中一个事实是export =
可以给您的东西是ES没有符合规范的导入方式,例如函数或类作为模块。为了解决这些不兼容问题,Babel允许您暂时导入CJS模块,就像默认情况下它们正在导出内容一样,或 import作为命名空间。 TypeScript暂时没有执行此操作,但最近在esModuleInterop
下将其作为选项添加。因此,现在Babel和TypeScript都可以非常一致地允许使用默认或名称空间ES导入来导入CJS模块。
使用TypeScript,它还取决于实际定义库的类型定义的方式。我不会对此进行介绍,但是您可以想象这样的情况:由于使用了编译器和捆绑器,特定的导入在运行时有效,但是TypeScript不会没有错误地进行编译。
值得一提的另一件事是,如果您查看React的内置代码,则有一个UMD module版本和CJS版本。 UMD版本包含一些粗糙的运行时代码,以尝试使其在任何模块环境(包括浏览器)中均可工作。如果您只想在运行时包含React(即您不使用捆绑程序),则主要用于此。 Example。
令人困惑?是的,我是这样认为的。 :)
答案 1 :(得分:2)
您很可能在"allowSyntheticDefaultImports": true,
中设置了tsconfig.json
,这实际上使编译器无法使用它认为无效的默认导入。 Typescript添加了esModuleInterop
,其本质上与babel进行模块加载一样。
即使您要导入的源代码未导出任何默认内容,这也允许您使用ES6默认导入
打字稿对此非常严格(遵循规则),这就是为什么它们要求您import * as React from 'react'
。或者要求您告诉它在其基本配置中允许合成默认导入。