Home  >  Q&A  >  body text

"Similarities and differences between import * as React from 'react'; and import React from 'react';"

<p>I noticed that <code>React</code> can be imported like this: </p> <pre class="brush:js;toolbar:false;">import * as React from 'react'; </pre> <p>...or import like this: </p> <pre class="brush:js;toolbar:false;">import React from 'react'; </pre> <hr /> <p>The first method imports all the contents of the <code>react</code> module (see: Importing the contents of the entire module)</p> <p>The second method only imports the <code>default</code> module export (see: Importing the default export)</p> <hr /> <p>The two approaches appear to be different and fundamentally incompatible. </p> <p>Why do they all work? </p> <hr /> <p>Please refer to the source code and explain the mechanism... I'm interested in understanding how this works. </p> <hr /> <p><strong>Update</strong></p> <p>This is not a duplicate question, it is different from "the difference between import * as react from 'react' vs import react from 'react'"</p> <p>That question is answered with general ES6 module information. </p> <p>I'm asking about the mechanism that enables the <code>react</code> module to work this way. It seems to have something to do with a "hacky" export mechanism in the source code, but it's not clear how it makes both ways of importing the entire module and just importing the default exports to <code>React</code> work with transpiled JSX etc. </p>
P粉596161915P粉596161915447 days ago511

reply all(2)I'll reply

  • P粉486138196

    P粉4861381962023-08-23 10:44:14

    You most likely have "allowSyntheticDefaultImports": true, set in your tsconfig.json file, which actually makes the compiler silent on default imports it deems invalid. Typescript adds esModuleInterop which is basically the same thing babel does in terms of module loading.

    This enables you to use ES6 default imports when the imported source code does not have a default export.

    Typescript is strict (follows the rules) in this regard, which is why it requires you to use import * as React from 'react'. Or require you to tell it in the base configuration to allow synthetic default imports.

    More related information

    reply
    0
  • P粉023650014

    P粉0236500142023-08-23 00:04:25

    TL;DR

    Actually, the ES import statement import default and import * are not the same thing. They behave the same in this case because the React author chose to do it this way. Publish the library and make it "just work" using a compatibility layer in TypeScript (using esModuleInterop) or Babel and the packaging tool. According to the ES6 spec, it probably shouldn't work properly, but today we're still in the age of JS module chaos, so tools like Babel, TypeScript, Webpack, etc. all try to standardize behavior.

    more details:

    React is not an ES6 library. If you look at the source code, you'll 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;

    (Note the comments, even in the React source code, they are working on compatibility issues with ES6 default exports.)

    module.exports =The syntax is that of CommonJS (NodeJS). The browser cannot understand this syntax. That's why we use packaging tools like Webpack, Rollup or Parcel. They understand various module syntaxes and generate bundled files that should work in the browser.

    However, even though React is not an ES library, both TypeScript and Babel allow you to import it like an ES library (using the import syntax, not require(), etc.) , but there are some differences between CJS and ES that need to be addressed. One of them is that export = can provide you with import methods that are not compliant with the ES specification, such as importing functions or classes as modules. To resolve these incompatibilities, Babel allows you to import CJS modules by default, or by namespace. TypeScript did not previously support this, but this option was recently added under esModuleInterop. So now both Babel and TypeScript fairly consistently allow importing CJS modules using default or namespace ES imports.

    For TypeScript, it also depends on how the library's type definition is defined. I won't go into details, but you can imagine that there are cases where a specific import will work fine at runtime due to the transpiler and packaging tools, but TypeScript will throw errors at compile time.

    Another thing worth mentioning is that if you look at React's build code, there is also a UMD module version as well as a CJS version. The UMD version contains some complex runtime code to make it work properly in any module environment, including browsers. It is mainly intended for use when only React is included in the runtime (i.e. no packaging tools are used). Example.

    Confusing? Yes, I think so too. :)

    reply
    0
  • Cancelreply