tsconfig.json文件說明
一般在 typescript 的項目中,我們都能看到 tsconfig.json 這個文件,它指定了此項目的編譯選項,也指定了此項目的根目錄,因此這個文件一般也是在項目的根目錄下。既然如此,就單單 typescript 項目而言,它的編譯一般有以下幾種方式:
-
命令行直接輸入
tsc命令不帶任何參數進行編譯:此時編譯器會從當前目錄開始查找
tsconfig.json文件,如果當前目錄沒有發現該文件,則逐級向父級目錄搜索。如果一直沒有檢索到該文件,編譯器會給出使用提示。 -
命令行調用
tsc帶參數--project(或 -p)而指定一個目錄:編譯器直接在該目錄下查找
tsconfig.json文件,如果沒找到則報錯。 -
命令行調用
tsc后直接指定文件:直接編譯指定的文件。
1. files
數組類型,用於表示由 ts 管理的 文件 的具體路徑,可以是相對或絕對路徑。這些文件內部有依賴的模塊(或者引入了哪些模塊),編譯器也會搜索到依賴模塊進行編譯。如果某些模塊並沒有在項目中引入,雖然在項目目錄中也不會被編譯。需要注意的是,files 中不支持 glob 匹配模式的路徑。
2. include 與 exclude
數組類型,include 用於表示 ts 管理的文件。exclude用於表示 ts 排除的文件(即不被編譯的文件)。其中的文件列表可以使用 glob 匹配模式列表,支持的glob通配符有:
*匹配0或多個字符(不包括目錄分隔符)?匹配一個任意字符(不包括目錄分隔符)**/遞歸匹配任意子目錄
注意,這三者的優先級是這樣的:files > exclude > include 。如果不指定 files ,項目目錄下的所有文件都會被編譯器編譯。如果同一個文件在三者中均指定,此文件一定會被編譯器編譯。而 files 中不指定而在 exclude、include 中同時指定的文件也會被編譯,因為優先級是這樣的 exclude > include 。另外,exclude默認情況下會排除node_modules,bower_components,jspm_packages 和 outDir 目錄。
3. compileOnSave
布爾類型,可以讓 IDE 在保存文件的時候根據 tsconfig.json 重新生成編譯后的文件。
4. extends
字符串類型,該值是一個路徑,指定另一個配置文件用於繼承 tsconfig.json 中的配置。在原文件里的配置最先被加載,原文件里的配置被繼承文件里的同名配置所重寫。 如果發現循環引用,則會報錯。
5. typeAcquisition
對象類型,設置自動引入庫類型定義文件。acquisition 翻譯過來是 “獲得物、獲得” 的意思。在整個項目中,如果存在用JavaScript寫的庫,ts 會自動去 compilerOptions.typeRoots 指定的目錄中尋找對應的類型聲明文件。這個行為被稱為 typeAcquisition (類型獲得)。這個行為可以通過enable來開啟或關閉,且以庫級別來指定應用的范圍。但我在實踐中,通過指定 enable 的值去控制這個行為並未有明顯的感官,即使使用 vscode 修改配置后重啟也並未生效。
當我使用 jquery 做測試的時候,將 enable 設為 false 且下載了 @types/jquery 的時候,vscode 並未提示無法找到該聲明,也無任何報錯。但當我將其設為 true,且刪除 @types/jquery時,vscode 仍未提示無法找到該聲明,鼠標懸浮引入的 jquery 提示在全局的 typescript/3.8/node_modules/@types/ 目錄下找到了該聲明。
這個配置項在平時的開發中並不常用,大家也不必深究。
6. watchOptions
對象類型,typescript3.8 以上新增加的配置,用來配置使用哪種監聽策略來跟蹤文件和目錄。由於 tsc 的監聽文件機制依賴於 node 的 fs.watch/fs.watchFile。這兩種方法的實現並不相同,前者是采用文件系統的事件做到通知,而后者使用輪詢的機制。更多可以查閱 node 官方文檔。
-
watchFile
字符串類型,配置單個文件的監聽策略,必須為一下幾個值:
- useFsEvents(默認):采用系統的文件系統的原生事件機制監聽文件更改
- useFsEventsOnParentDirectory:采用系統的文件系統的原生事件機制監聽修改文件所在的目錄,這樣修改一個文件實際上監聽的是此文件所在的目錄都被監聽了,如此整個項目的文件監聽器將顯著減少,但可能導致監聽並不准確。
- dynamicPriorityPolling:創建一個動態隊列去監聽文件,修改頻率較低的文件將被減少輪詢監聽的頻率。
- fixedPollingInterval:固定間隔的檢查每個文件是否發生變化。
- priorityPollingInterval:固定間隔的檢查每個文件是否發生變化,但使用啟發式監聽的文件的檢查頻率要低於非啟發式監聽的文件。
-
watchDirectory
字符串類型,配置監聽目錄的策略,必須為以下幾個值:
- useFsEvents(默認)
- dynamicPriorityPolling
- fixedPollingInterval
以上三個和
watchFile中相差不多 -
fallbackPolling
當采用系統的文件系統中原生事件機制監聽文件時,此選項指定本機的文件監聽器被耗盡或者不支持本機文件監聽器是編譯器采用的輪詢策略,可以設置為以下幾個值:
- fixedPollingInterval
- dynamicPriorityPolling
- priorityPollingInterval
- synchronousWatchDirectory:禁用對目錄的延遲監聽。如果有大量的文件更改,比如在
npm install時node_modules目錄發生的變化,延遲監聽是非常有用的。但總有些不常見的場景需要禁用延遲監聽。
-
synchronousWatchDirectory
布爾類型,是否對目錄延遲監聽。如果配置為
true,當文件發生修改時同步的調用回調並更新目錄監聽器。 -
excludeFiles
字符串數組,用於指定不需要被監聽變化的文件
-
excludeDirectories
字符串數組,用於指定不需要被監聽變化的目錄
7. reference
項目引用是TypeScript3.0的新特性,它支持將TypeScript程序的結構分割成更小的組成部分。
這是 typescript 官網中的描述,那怎么理解這句話呢。我們通過一個場景認識新出這種的 reference 特性。
假設我們要開發一個類似於 lodash 的工具庫,並在項目中使用,而且后期很有可能還要在業界推廣。為了保證這個工具的順利開發及推廣,我們必須要做相應的單元測試。那這個工具庫可以看做一個項目,對其中的每個功能的測試也可作為一個獨立的項目。但整個過程中,工具庫的開發和測試應該是屬於同一個項目下 “分項目” 的。那這種情況下 reference 就很棒了。首先我們搭一個目錄出來:
|---- src/
|---- index.ts // 整個工具庫的入口
|---- copyDeep.ts // 其中定義了copyDeep方法
|---- test/
|---- copyDeep.test.ts // copyDeep的單元測試
|---- package.json
|---- tsconfig.json
在 copyDeep.test.ts 中肯定要引用 src/copyDeep,也就是說 test 的項目是依賴於 src 的。如果 src 中的代碼發生了變化,整個工具庫項目應該重新編譯,而 test 項目不應該再被編譯,這本來就是合理的。如果 test 項目中的代碼發生了變化,那 test 項目應該被重新編譯,而 src 項目不應該再被編譯。如何在一個項目中配置而做到分別編譯相應的子項目呢?首先最先想到的應該是在 tsconfig.json 文件中引入 include 字段配置,我們先嘗試一下下面的配置:
{
"files": [
"./src/index.ts"
],
"include": [
"./test/**/*.test.ts"
],
"compilerOptions": {
"outDir": "./dist/"
}
}
我們來分析這樣配置的會有哪些問題:
- 首先,從整個項目層面,確實做到了修改任意文件重新編譯的功能。但注意,編譯的是全量的
ts文件。 - 隨着日后項目的增大,在
*.test.ts文件中引入也將逐漸變大。 - 修改了
src//**/*.ts的內容,test/**/*.ts也將作為輸出,這是我們不希望看到的。
此時,reference 將解決上述的每一個問題,我們修改項目結構如下:
|---- src/
|---- index.ts // 整個工具庫的入口
|---- copyDeep.ts // 其中定義了copyDeep方法
|---- tsconfig.json // 工具庫的編譯配置文件
|---- test/
|---- copyDeep.test.ts // copyDeep的單元測試
|---- tsconfig.json // 測試的編譯配置文件
|---- package.json
|---- tsconfig.json
並修改為以下配置:
// 根目錄下的 /tsconfig.json
{
"compilerOptions": {
"declaration": true, // 為子項目生成.d.ts聲明文件
"outDir": "./dist",
}
}
// src目錄下的 /src/tsconfig.json
{
"extends": "../tsconfig",
"compilerOptions": {
"composite": true // 必須設置為true,表明該文件夾為一個子項目
}
}
// test目錄下的 /src/tsconfig.json
{
"extends": "../tsconfig",
"references": [
{ "path": "../src" } // 表示引用了工具庫項目
]
}
這樣配置后,如果 src 項目已經編譯完成並且輸出了編譯后的文件, 那在 test 項目中,實際加載的是 src 項目聲明的 .d.ts 文件,而且這個聲明文件是對 test 項目可見的。另外,如果開啟了 watch 模式,修改了內容只會編譯相應的項目而不會全量編譯。這會顯著的加速類型檢查和編譯,減少編輯器的內存占用。而且在代碼結構層命有了一個很清晰的規划。
總結來講,refrence 的作用是將兩個項目關聯起來作為一個項目開發,當某個項目代碼修改后還能單獨編譯相應的項目而不是整個項目。再說的簡單點,就是實現了關聯項目間的懶編譯。
總結
本篇文章先到這里,總結一下:tsconfig.json 這個文件是用來界定 ts 項目的根目錄,也用來配置 tsc 在編譯 ts 文件時的一些選項。files、exclude、include 用來配置需要編譯哪些文件;compilerOnSave 是指定 IDE 保存后是否重新編譯的;extends 用來擴展當前的配置;擴展配置文件中的字段會覆蓋當前文件的相同字段;typeAcquisition 用來指定某些庫的類型聲明文件,如:
"typeAcquisition": {
"jquery": "@/types/jquery"
}
watchOptions 用來配置 tsc 的監聽策略;reference 指定關聯項目,從而提高編譯速度。
