问题描述
我注意到 React
可以像这样导入:
I've noticed that React
can be imported like this:
import * as React from 'react';
...或者像这样:
import React from 'react';
第一个导入 react
模块中的所有内容(参见:导入整个模块的内容)
The first imports everything in the react
module (see: Import an entire module's contents)
第二个仅导入 default
模块导出(请参阅:导入默认值)
The second imports only the default
module export (see: Importing defaults)
这两种方法似乎不同,而且根本不兼容.
It seems like the two approaches are different and fundamentally incompatible.
为什么它们都有效?
请参考源代码并解释机制...我有兴趣了解其工作原理.
Please reference the source code and explain the mechanism...I'm interested in understanding how this works.
更新
这不是import * as react from 'react' 与 import react from 'react' 有什么区别
这个问题的回答是一般的 ES6 模块信息.
That question was answered with general ES6 module information.
我问的是使 react
模块像这样工作的机制.它似乎与hacky"导出机制有关 在此处的源代码中,但尚不清楚如何同时导入整个模块和仅将默认导出到React
并具有这两种方法都适用于转译 JSX 等.
I am asking about the mechanism that makes the react
module work like this. It seems to be related to "hacky" export mechanism in the source here but it's not clear how that enables both importing the entire module and just the default export into React
and having both of those approaches work with transpiling JSX, etc.
推荐答案
TL;DR
确实 ES 导入语句 import default
和 import *
不是一回事,在这种情况下它们的行为相同的事实是 React 作者选择的方式的组合在 TypeScript(使用 esModuleInterop
)或 Babel 和你的打包器中发布库和兼容层,使它们正常工作".根据 ES6 规范,它可能不应该工作,但今天我们仍然工作在一个 JS 模块一团糟的时代,因此 Babel、TypeScript、Webpack 等工具试图规范行为.
TL;DR
Indeed ES import statements import default
and import *
are not the same thing, the fact that they behave the same in this case is a combination of how React authors chose to publish the library and compatibility layers in TypeScript (using esModuleInterop
) or Babel and your bundler to make them "just work". It probably shouldn't work according to ES6 spec, but today we are still working in an era where JS modules are a mess, so tools like Babel, TypeScript, Webpack, etc try to normalize behavior.
React 不是 ES6 库.如果您查看源代码,您会在index.js
:
React is not an ES6 library. If you look at the source code you see this in 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 默认导出兼容性有问题.)
(Note the comment, even in React source code they struggle with ES6 default export compatibility.)
module.exports =
语法是 CommonJS (NodeJS).浏览器不会理解这一点.这就是我们使用 Webpack、Rollup 或 Parcel 等打包器的原因.他们了解各种模块语法并生成应该在浏览器中工作的包.
The module.exports =
syntax is CommonJS (NodeJS). A browser would not understand this. This is why we use bundlers like Webpack, Rollup, or Parcel. They understand all kinds of module syntax and produce bundles that should work in the browser.
但即使 React 不是 ES 库,TypeScript 和 Babel 都允许您将其导入(使用 import
语法,而不是 require()
,等),但 CJS 和 ES 之间存在必须解决的差异.其中之一是 export =
可以 为您提供 ES 没有符合规范的导入方式的东西,例如作为模块的函数或类.为了解决这些不兼容问题,Babel 允许您导入 CJS 模块,就像它们默认导出某些东西一样,或导入为命名空间.TypeScript 有一段时间没有这样做,但最近将其添加为 esModuleInterop
下的一个选项.所以现在 Babel 和 TypeScript 都可以非常一致地允许使用默认或命名空间 ES 导入来导入 CJS 模块.
But even though React is not an ES library, both TypeScript and Babel let you import it as if it is (using import
syntax, rather than require()
, etc), but there are differences between CJS and ES that have to be resolved. One of them is the fact that export =
can give you things that ES has no spec-compliant way to import, like a function or a class as the module. To work around these incompatibilities Babel has for awhile allowed you to import CJS modules as if they were exporting something by default, or import as a namespace. TypeScript for awhile didn't do this, but more recently added that as an option under esModuleInterop
. So now both Babel and TypeScript can pretty consistently allow a CJS module to be imported using default or namespace ES imports.
对于 TypeScript,它还取决于库的类型定义是如何实际定义的.我不会讨论这个,但你可以想象这样的情况:多亏了转译器和打包器,特定的导入在运行时有效,但 TypeScript 编译时不会出错.
With TypeScript it also depends on how the type-definitions for the library are actually defined. I won't get into that, but you can imagine situations where thanks to transpilers and bundlers a particular import works at runtime, but TypeScript doesn't compile without errors.
另一件值得一提的事情是,如果您查看 React 的构建代码,则有一个 UMD 模块版本以及 CJS 版本.UMD 版本包含一些粗糙的运行时代码,试图使其在任何模块环境中工作,包括浏览器.它主要用于如果您只想在运行时包含 React(即您不使用捆绑器).示例.
Another thing worth mentioning is that if you look at the built code for React there is a UMD module version as well as the CJS version. The UMD version includes some gnarly runtime code to try to make it work in any module environment, including the browser. It's mainly for use if you want to just include React at runtime (ie you don't use a bundler). Example.
令人困惑?是的,我想是的.:)
Confusing? Yeah, I think so. :)
这篇关于import * as React from 'react';vs 从“反应"导入反应;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!