我注意到React可以这样导入:
React
import * as React from 'react';
…或像这样:
import React from 'react';
第一个导入模块中的所有内容react(请参阅:导入整个模块的内容)
react
第二个仅导入default模块导出(请参阅:导入默认值)
default
似乎这两种方法是不同的,并且根本上是不兼容的。
为什么它们都起作用?
请参考源代码并解释该机制…我有兴趣了解其工作原理。
ES6常规模块信息回答了该问题。
我在问使react模块像这样工作的机制。在这里,它似乎与源代码中的 “ hacky”导出机制有关,但尚不清楚如何将 整个 模块导入到 默认的 导出中React,以及如何将这两种方法与转译JSX等一起使用。
事实上,ES import语句import default和import *不一样的东西,他们的行为在这种情况下,同样的事实是如何反应作者选择发布的库和兼容层以打字稿联合使用(使用esModuleInterop)或巴贝尔和你捆绑,使他们“正常工作”。根据ES6规范,它可能 不应该 工作,但是今天,我们仍处于一个JS模块混乱的时代,因此Babel,TypeScript,Webpack等工具试图规范行为。
import default
import *
esModuleInterop
React不是ES6库。如果您查看源代码,则会在以下代码中看到它index.js:
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之类的捆绑器的原因。他们了解各种模块语法,并产生应在浏览器中工作的捆绑软件。
module.exports =
但是,尽管React不是ES库,但TypeScript和Babel都允许您将其导入为原样(使用import语法,而不是require(),等等),但是CJS和ES之间必须解决差异。其中一个事实是,您export = 可以 得到ES没有符合规范的导入方式,例如函数或类作为模块。为了解决这些不兼容问题,Babel允许您暂时导入CJS模块,就像默认情况下它们正在导出某些内容一样, 或者 作为命名空间导入。TypeScript暂时没有执行此操作,但最近在下方将其添加为一个选项esModuleInterop。因此,现在Babel和TypeScript都可以非常一致地允许使用默认或名称空间ES导入来导入CJS模块。
import
require()
export =
使用TypeScript,它还取决于实际定义库的类型定义的方式。我不愿赘述,但是您可以想象这样的情况:由于使用了编译器和捆绑器,特定的导入 可以在运行时进行 ,但是TypeScript不会没有错误地进行编译。
值得一提的另一件事是,如果您查看React的内置代码,则有UMD模块版本和CJS版本。UMD版本包含一些粗糙的运行时代码,以尝试使其在任何模块环境(包括浏览器)中都能工作。如果您只想在运行时包含React(即您不使用捆绑程序),则主要用于此。实例。
令人困惑?是的,我是这样认为的。:)