Vyhledávání na webu

javascript - import * as React z 'react'; vs import React z 'react';


Všiml jsem si, že React lze importovat takto:

import * as React from 'react';

...nebo takto:

import React from 'react';

První importuje vše v modulu react (viz: Import celého obsahu modulu)

Druhý importuje pouze výchozí (default) export modulu (viz: Importování výchozích hodnot)

Zdá se, že tyto dva přístupy jsou odlišné a zásadně neslučitelné.

Proč oba fungují?

Prosím, odkažte se na zdrojový kód a vysvětlete mechanismus... Zajímá mě, jak to funguje.

Aktualizace

Toto není duplicitní otázka k „Jaký je rozdíl mezi import * as react from 'react' vs import react from 'react'“

Na tuto otázku byla odpovězena obecnými informacemi o modulech ES6.

Ptám se na mechanismus, který způsobuje, že modul react funguje tímto způsobem. Zdá se, že to souvisí s "hackerským" mechanismem exportu ve zdrojovém kódu zde, ale není jasné, jak to umožňuje jak importování celého modulu, tak jen výchozího exportu do React a jak obě tyto možnosti fungují při transpilu JSX atd.

Odpověď č. 1

Stručně

Skutečně, ES importní příkazy import default a import * nejsou totéž; fakt, že se v tomto případě chovají stejně, je kombinací toho, jak autoři Reactu zvolili publikování knihovny, a vrstev kompatibility v TypeScriptu (při použití esModuleInterop) nebo v Babelu a vašem bundleru, aby „jen fungovaly“. Pravděpodobně podle specifikace ES6 by to nemělo fungovat, ale dnes stále pracujeme v éře, kdy jsou JS moduly chaotické, takže nástroje jako Babel, TypeScript, Webpack atd. se snaží chování sjednotit.

Více podrobností:

React není knihovna ES6. Pokud se podíváte na zdrojový kód, uvidíte toto v 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;

(Všimněte si komentáře, dokonce i v kódu Reactu mají problémy s kompatibilitou výchozího exportu ES6.)

Syntaxe module.exports = je CommonJS (NodeJS). Prohlížeč by tomu nerozuměl. Proto používáme balíčkovací nástroje jako Webpack, Rollup nebo Parcel. Ty rozumí všem druhům syntaktických modulů a vytvářejí balíčky, které by měly fungovat v prohlížeči.

Ale i když React není knihovna ES, jak TypeScript, tak Babel vám umožňují ji importovat, jako by byla (pomocí syntaxe import, místo require() atd.), ale existují rozdíly mezi CJS a ES, které je potřeba vyřešit. Jedním z nich je fakt, že export = může vám poskytnout věci, které ES nemá způsob, jak importovat podle specifikace, například funkci nebo třídu jako modul. Aby se obešly tyto nekompatibility, Babel vám již chvíli dovoluje importovat CJS moduly, jako by exportovaly něco ve výchozím nastavení, nebo importovat je jako namespace. TypeScript to chvíli nedělal, ale nedávno přidal tuto možnost pod esModuleInterop. Takže nyní jak Babel, tak TypeScript dokáží docela konzistentně umožnit import CJS modulu pomocí výchozích nebo namespace ES importů.

U TypeScriptu také záleží na tom, jak jsou vlastně definovány typové definice pro knihovnu. Nebudu se do toho pouštět, ale můžete si představit situace, kdy díky transpilerům a bundlerům konkrétní import funguje při běhu programu, ale TypeScript se bez chyb nesestaví.

Další věc, kterou stojí za zmínku, je, že pokud se podíváte na sestavený kód pro React, existuje verze modulu UMD stejně jako verze CJS. Verze UMD zahrnuje nějaký komplikovaný spouštěcí kód, který se snaží zajistit, aby fungoval v jakémkoli modulovém prostředí, včetně prohlížeče. Je hlavně určena pro použití, pokud chcete React jen zahrnout při běhu (tj. nepoužíváte žádný balíčkovač). Příklad.

Zmatené? Jo, myslím, že ano. :)

Odpověď č. 2

Ve vašem tsconfig.json pravděpodobně máte nastaveno "allowSyntheticDefaultImports": true,, což v podstatě umlčí kompilátor ohledně defaultních importů, které považuje za neplatné. TypeScript přidal esModuleInterop, což v podstatě dělá to, co Babel pro načítání modulů.

To vám umožňuje používat výchozí importy ES6, i když zdrojový kód, který importujete, nic jako výchozí neexportuje

Typescript je v tomto přísný (dodržuje pravidla), proto od vás vyžaduje, abyste import * as React from 'react'. Nebo vyžaduje, abyste mu v základní konfiguraci řekli, aby povolil syntetické výchozí importy.

Více o tom zde

Související články