專案參考是 TypeScript 3.0 中的新功能,可讓您將 TypeScript 程式結構化為更小的部分。
藉此,您可以大幅縮短建置時間、強制執行元件之間的邏輯區隔,並以更佳且更有效率的方式整理您的程式碼。
我們也為 tsc
導入新的模式,即 --build
旗標,它與專案參考攜手合作,以加快 TypeScript 建置。
範例專案
讓我們來看看一個相當正常的程式,以及專案參考如何幫助我們更有效率地整理它。假設您有一個專案包含兩個模組,converter
和 units
,以及每個模組對應的測試檔案
/ ├── src/ │ ├── converter.ts │ └── units.ts ├── test/ │ ├── converter-tests.ts │ └── units-tests.ts └── tsconfig.json
測試檔案會匯入實作檔案並執行一些測試
ts
// converter-tests.tsimport * as converter from "../src/converter";assert.areEqual(converter.celsiusToFahrenheit(0), 32);
之前,如果您使用單一 tsconfig 檔案,這個結構會相當難以使用
- 實作檔案可以匯入測試檔案
- 無法同時建置
test
和src
,而不會讓src
出現在輸出資料夾名稱中,這可能不是您想要的 - 僅變更實作檔案中的內部結構,就需要再次類型檢查測試,即使這不會造成任何新的錯誤
- 僅變更測試,就需要再次類型檢查實作,即使沒有任何變更
您可以使用多個 tsconfig 檔案來解決部分這些問題,但會出現新的問題
- 沒有內建的最新檢查,因此您最終會一直執行
tsc
兩次 - 呼叫
tsc
兩次會產生更多啟動時間開銷 tsc -w
無法同時執行多個設定檔
專案參考可以解決所有這些問題,甚至更多問題。
專案參考是什麼?
tsconfig.json
檔案有一個新的頂層屬性,references
。它是一個物件陣列,用來指定要參照的專案
js
{"compilerOptions": {// The usual},"references": [{ "path": "../src" }]}
每個參考的 path
屬性可以指向包含 tsconfig.json
檔案的目錄,或指向設定檔本身(可以是任何名稱)。
當您參照一個專案時,會發生新的事情
- 從參照專案匯入模組,將會載入其輸出宣告檔 (
.d.ts
) - 如果參照專案產生
outFile
,輸出檔案.d.ts
檔的宣告將會顯示在此專案中 - 建置模式(請見下方)會在需要時自動建置參照專案
透過分隔成多個專案,您可以大幅提升類型檢查和編譯的速度,在使用編輯器時減少記憶體用量,並改善程式邏輯分組的強制執行。
composite
參照專案必須啟用新的 composite
設定。需要這個設定才能確保 TypeScript 能快速找出參照專案輸出的位置。啟用 composite
旗標會改變一些事情
- 如果未明確設定,
rootDir
設定值會預設為包含tsconfig
檔案的目錄 - 所有實作檔案都必須符合
include
模式或列於files
陣列中。如果違反此約束,tsc
會通知您未指定的檔案 - 必須開啟
declaration
declarationMap
我們也已新增對 宣告來源對應 的支援。如果您啟用 declarationMap
,您就能使用「前往定義」和重新命名等編輯器功能,在受支援的編輯器中跨專案邊界透明地瀏覽和編輯程式碼。
prepend
搭配 outFile
您也可以使用參考中的 prepend
選項,啟用將相依項的輸出置於前面
js
"references": [{ "path": "../utils", "prepend": true }]
置於前面的專案會將專案的輸出包含在目前專案的輸出之前。所有輸出檔案 (.js
、.d.ts
、.js.map
、.d.ts.map
) 都會正確發出。
tsc
僅會使用磁碟上的現有檔案來執行此處理程序,因此有可能建立一個專案,其中無法產生正確的輸出檔案,因為某些專案的輸出會在結果檔案中出現多次。例如
txt
A ^ ^ / \ B C ^ ^ \ / D
在這種情況下,不要在每個參考中都置於前面,因為您最終會在 D
的輸出中得到兩個 A
的副本 - 這可能會導致意外的結果。
專案參考的注意事項
專案參考有一些您應該注意的取捨。
由於相依專案使用由其相依項建置的 .d.ts
檔案,因此您必須檢查某些建置輸出或在複製專案後建置專案,然後才能在編輯器中瀏覽專案,而不會看到虛假錯誤。
在使用 VS Code 時(自 TS 3.7 起),我們有一個幕後記憶體內 .d.ts
產生程序,應該能夠減輕這個問題,但它有一些效能影響。對於非常大型的複合專案,您可能想使用 disableSourceOfProjectReferenceRedirect 選項 來停用此功能。
此外,為了保持與現有建置工作流程的相容性,tsc
在未搭配 --build
開關呼叫時不會自動建置相依項。讓我們進一步了解 --build
。
TypeScript 的建置模式
TypeScript 專案中備受期待的功能是智慧增量建置。在 3.0 中,您可以將 --build
旗標與 tsc
搭配使用。這實際上是 tsc
的新進入點,其行為更像是建置協調器,而非簡單的編譯器。
執行 tsc --build
(簡寫為 tsc -b
)會執行下列動作
- 尋找所有參考的專案
- 偵測它們是否為最新版本
- 依正確順序建置過期的專案
您可以提供多個設定檔路徑給 tsc -b
(例如 tsc -b src test
)。就像 tsc -p
一樣,如果設定檔名稱為 tsconfig.json
,則不需要指定設定檔名稱。
tsc -b
命令列
您可以指定任意數量的設定檔
shell
> tsc -b # Use the tsconfig.json in the current directory> tsc -b src # Use src/tsconfig.json> tsc -b foo/prd.tsconfig.json bar # Use foo/prd.tsconfig.json and bar/tsconfig.json
別擔心命令列中傳遞檔案的順序,tsc
會在需要時重新排序,以確保依賴項優先建置。
tsc -b
還有一些特定旗標
--verbose
:列印詳細記錄,說明正在執行什麼作業(可與任何其他旗標合併使用)--dry
:顯示將執行的動作,但實際上不會建置任何內容--clean
:刪除指定專案的輸出(可與--dry
合併使用)--force
:視同所有專案都已過時--watch
:監控模式(不可與任何旗標合併使用,但--verbose
除外)
注意事項
通常,tsc
會在存在語法或型別錯誤的情況下產生輸出(.js
和 .d.ts
),除非已啟用 noEmitOnError
。在增量建置系統中執行此操作會非常糟糕,如果過時的依賴項之一出現新錯誤,您只會看到一次,因為後續建置會略過現在已更新的專案。因此,tsc -b
實際上會作用於所有專案,就像已啟用 noEmitOnError
一樣。
如果您檢查任何建置輸出(.js
、.d.ts
、.d.ts.map
等),您可能需要在某些原始碼控制作業後執行 --force
建置,具體取決於您的原始碼控制工具是否在本地副本和遠端副本之間保留時間戳記。
MSBuild
如果您有 msbuild 專案,您可以透過加入以下內容來啟用建置模式
xml
<TypeScriptBuildMode>true</TypeScriptBuildMode>
至您的 proj 檔案。這將會啟用自動增量建置以及清理。
請注意,與 tsconfig.json
/ -p
一樣,現有的 TypeScript 專案屬性將不會受到尊重 - 所有設定都應該使用您的 tsconfig 檔案進行管理。
有些團隊已經設定好基於 msbuild 的工作流程,其中 tsconfig 檔案與其配對的受管理專案具有相同的隱含圖形排序。如果您的解決方案是這樣,您可以繼續將 msbuild
與 tsc -p
搭配專案參考一起使用;這些是完全可以互通的。
指南
整體結構
隨著 tsconfig.json
檔案越來越多,您通常會想要使用 組態檔繼承 來集中您的常見編譯器選項。這樣一來,您就可以在一個檔案中變更設定,而不用編輯多個檔案。
另一個良好的做法是有一個「解決方案」tsconfig.json
檔案,其中僅包含 references
至您所有葉節點專案,並將 files
設定為一個空陣列(否則解決方案檔案將導致檔案重複編譯)。請注意,從 3.0 開始,如果您在 tsconfig.json
檔案中至少有一個 reference
,則 files
陣列為空不再會是錯誤。
這提供了一個簡單的進入點;例如,在 TypeScript 儲存庫中,我們只需執行 tsc -b src
即可建置所有端點,因為我們在 src/tsconfig.json
中列出所有子專案
您可以在 TypeScript 儲存庫中看到這些模式 - 查看 src/tsconfig_base.json
、src/tsconfig.json
和 src/tsc/tsconfig.json
作為關鍵範例。
結構化相對模組
一般來說,轉換使用相對模組的儲存庫不需要做太多事。只要在指定父資料夾的每個子目錄中放置一個 tsconfig.json
檔案,並將 reference
加入這些設定檔,以符合程式預期的分層。你需要將 outDir
設定為輸出資料夾的明確子資料夾,或將 rootDir
設定為所有專案資料夾的共用根目錄。
結構化 outFiles
使用 outFile
編譯的配置較為彈性,因為相對路徑沒有那麼重要。需要注意的是,通常你會希望不要在「最後」一個專案之前使用 prepend
- 這樣可以縮短建置時間,並減少任何指定建置所需的 I/O 量。TypeScript 儲存庫本身就是一個很好的參考 - 我們有一些「程式庫」專案和一些「端點」專案;「端點」專案盡可能保持精簡,並且只提取他們需要的程式庫。