"import * as React from 'react'; 與 import React from 'react'; 的異同"
P粉596161915
2023-08-22 19:59:28
<p>我注意到<code>React</code>可以這樣導入:</p>
<pre class="brush:js;toolbar:false;">import * as React from 'react';
</pre>
<p>...或這樣導入:</p>
<pre class="brush:js;toolbar:false;">import React from 'react';
</pre>
<hr />
<p>第一種方式導入了<code>react</code>模組的所有內容(請參閱:導入整個模組的內容)</p>
<p>第二種方式只匯入了<code>default</code>模組匯出(見:匯入預設匯出)</p>
<hr />
<p>這兩種方式似乎是不同且根本上不相容的。 </p>
<p>為什麼它們都能運作? </p>
<hr />
<p>請參考原始碼並解釋機制...我對了解這是如何工作感興趣。 </p>
<hr />
<p><strong>更新</strong></p>
<p>這不是重複的問題,不同於「import * as react from 'react' vs import react from 'react'的區別」</p>
<p>那個問題是透過一般的ES6模組資訊回答的。 </p>
<p>我問的是讓<code>react</code>模組能夠這樣運作的機制。它似乎與原始程式碼中的「hacky」匯出機制有關,但不清楚它如何使匯入整個模組和只匯入預設匯出到<code>React</code>的兩種方式都能與轉譯JSX等運作。 </p>
你的
tsconfig.json
檔案中很可能設定了"allowSyntheticDefaultImports": true,
,這實際上讓編譯器對它認為無效的預設導入保持靜默。 Typescript 增加了esModuleInterop
,它基本上與 babel 在模組載入方面所做的事情相同。這使你能夠在導入的源代碼沒有預設導出時使用 ES6 預設導入。
Typescript 在這方面是嚴格的(遵循規則),這就是為什麼它要求你使用
import * as React from 'react'
。或要求你在基本配置中告訴它允許合成預設導入。更多相關資訊
#TL;DR
實際上,ES的import語句
import default
和import *
並不是同一回事,它們在這種情況下表現相同是因為React作者選擇以這種方式發布庫並在TypeScript(使用esModuleInterop
)或Babel以及打包工具中使用相容層使其「正常工作」。根據ES6規範,它可能不應該正常工作,但是今天我們仍然處於JS模組混亂的時代,因此像Babel、TypeScript、Webpack等工具都試圖規範行為。更多細節:
React不是一個ES6函式庫。如果你查看原始碼,你會在
index.js
#中看到這個:(注意註釋,即使在React原始碼中,他們也在努力解決ES6預設導出的兼容性問題。)
module.exports =
語法是CommonJS(NodeJS)的語法。瀏覽器無法理解這個語法。這就是為什麼我們使用像Webpack、Rollup或Parcel這樣的打包工具。它們理解各種模組語法,並產生應該在瀏覽器中工作的打包檔案。但是,儘管React不是一個ES庫,但是TypeScript和Babel都允許你像導入ES庫一樣導入它(使用
import
語法,而不是require()
等) ,但是CJS和ES之間存在一些需要解決的差異。其中之一是export =
可以提供你ES沒有規範相容的導入方式,例如將函數或類別作為模組導入。為了解決這些不相容性問題,Babel允許你以預設方式導入CJS模組,或以命名空間方式導入。 TypeScript以前不支援這樣做,但最近在esModuleInterop
下新增了這個選項。因此,現在Babel和TypeScript都可以相當一致地允許使用預設或命名空間ES導入來導入CJS模組。對於TypeScript來說,也取決於函式庫的類型定義是如何定義的。我不會詳細介紹,但你可以想像在某些情況下,由於轉譯器和打包工具的原因,特定的導入在運行時可以正常工作,但TypeScript在編譯時會出現錯誤。
另一個值得一提的事情是,如果你查看React的建置程式碼,還有一個UMD模組版本以及CJS版本。 UMD版本包含一些複雜的執行時間程式碼,以使其在任何模組環境中(包括瀏覽器)正常運作。它主要用於在運行時僅包含React(即不使用打包工具)的情況下使用。 範例。
令人困惑嗎?是的,我也這麼認為。 :)