欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

tsc性能優(yōu)化Project References使用詳解

 更新時(shí)間:2022年11月14日 09:08:44   作者:草帽Plasticine  
這篇文章主要為大家介紹了tsc性能優(yōu)化Project References使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

什么是 Project References

在了解一個(gè)東西是什么的時(shí)候,直接看其官方定義是最直觀的

TypeScript: Documentation中對(duì)于Project References的介紹如下:

Project references are a new feature in TypeScript 3.0 that allow you to structure your TypeScript programs into smaller pieces.

這是TypeScript 3.0新增的特性,這個(gè)特性有啥用呢?

將我們的項(xiàng)目分成多個(gè)小的片段,也就是允許我們將項(xiàng)目進(jìn)行分包模塊化

這樣一來我們?cè)趫?zhí)行tsc對(duì)項(xiàng)目進(jìn)行構(gòu)建的時(shí)候,無論是出于代碼轉(zhuǎn)譯成js的目的還是說出于單純的類型檢查(將compilerOptions.noEmit置為true)的目的

都可以嚴(yán)格按照自己的需要對(duì)想要被tsc處理的那部分代碼進(jìn)行處理,而不是每次都對(duì)整個(gè)項(xiàng)目進(jìn)行處理,這是我認(rèn)為Project References的最大好處

就以一個(gè)前后端代碼在同一個(gè)倉(cāng)庫(kù)里維護(hù)的項(xiàng)目為例,如果沒有Project References,那么我執(zhí)行tsc時(shí),會(huì)對(duì)前后端模塊都進(jìn)行類型檢查和轉(zhuǎn)譯

但實(shí)際上如果我只修改了前端部分的代碼,理所應(yīng)當(dāng)讓tsc只處理前端模塊,后端模塊的構(gòu)建產(chǎn)物不需要進(jìn)行重新構(gòu)建,有了Project References,我們就能實(shí)現(xiàn)到這個(gè)需求,從而優(yōu)化項(xiàng)目的構(gòu)建或類型檢查性能

相信大家對(duì)Project References有一個(gè)大概的認(rèn)識(shí)了,接下來我們就開始實(shí)際動(dòng)手體驗(yàn)一下Project References加深我們對(duì)它的理解吧!

示例項(xiàng)目結(jié)構(gòu)

.
├── package.json
├── pnpm-lock.yaml
├── src
│   ├── __test__              // 單元測(cè)試
│   │   ├── client.test.ts    // 前端代碼測(cè)試
│   │   ├── index.ts          // 簡(jiǎn)陋的單元測(cè)試 API
│   │   └── server.test.ts    // 后端代碼測(cè)試
│   ├── client                // 前端模塊
│   │   └── index.ts
│   ├── server                // 后端模塊
│   │   └── index.ts
│   └── shared                // 共享模塊 -- 包含通用的工具函數(shù)
│       └── index.ts
└── tsconfig.json             // TypeScript 配置

這是一個(gè)很常見的項(xiàng)目目錄結(jié)構(gòu),有前端代碼,有后端代碼,也有通用工具函數(shù)代碼以及前后端的單元測(cè)試代碼

它們的依賴關(guān)系如下:

  • client 依賴 shared
  • server 依賴 shared
  • __test__ 依賴 client 和 server
  • shared 無依賴

不使用 Project References 帶來的問題

現(xiàn)在整個(gè)項(xiàng)目只有一個(gè)tsconfig.json位于項(xiàng)目根目錄下,其內(nèi)容如下:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "CommonJS",
    "strict": true,
    "outDir": "./dist"
  }
}

如果我們執(zhí)行tsc,它會(huì)將各個(gè)模塊的代碼都打包到項(xiàng)目根目錄的dist目錄下

dist
├── __test__
│   ├── client.test.js
│   ├── index.js
│   └── server.test.js
├── client
│   └── index.js
├── server
│   └── index.js
└── shared
    └── index.js

這有一個(gè)很明顯的問題,正如前面所說,當(dāng)我們只修改一個(gè)模塊,比如只修改了前端模塊的代碼,那么理應(yīng)只需要再構(gòu)建前端模塊的產(chǎn)物即可,但是無論改動(dòng)范圍如何,都是會(huì)將整個(gè)項(xiàng)目都構(gòu)建一次,這在項(xiàng)目規(guī)模變得越來越大的時(shí)候會(huì)帶來極大的性能問題,構(gòu)建時(shí)長(zhǎng)會(huì)變得特別長(zhǎng)

或許你會(huì)想著在每個(gè)模塊里創(chuàng)建一個(gè)tsconfig.json,然后通過tsc -p指定每個(gè)模塊的目錄去單獨(dú)對(duì)它們進(jìn)行構(gòu)建,沒錯(cuò),這是一種解決方案

但是這會(huì)帶來下面兩個(gè)問題:

  • 如果需要全量構(gòu)建項(xiàng)目,你得需要運(yùn)行三次tsc,對(duì)每個(gè)模塊分別構(gòu)建,而tsc的啟動(dòng)時(shí)間開銷是比較大的,在這個(gè)小規(guī)模項(xiàng)目里甚至啟動(dòng)開銷的時(shí)間比實(shí)際構(gòu)建的時(shí)間更長(zhǎng),現(xiàn)在還只是運(yùn)行三次tsc,如果項(xiàng)目模塊很多,有幾十上百個(gè)呢?那光是啟動(dòng)tsc幾十上百次都已經(jīng)會(huì)花一些時(shí)間了
  • tsc -w不能一次監(jiān)控多個(gè)tsconfig.json,只能是對(duì)各個(gè)模塊都啟動(dòng)一次tsc -w

Project References的出現(xiàn),就是為了解決上述問題的

tsconfig.json 的 references 配置項(xiàng)

Project References就是tsconfig.json里的references配置項(xiàng),其結(jié)構(gòu)是一個(gè)包含若干對(duì)象的數(shù)組,對(duì)象的結(jié)構(gòu)如下:

{
  "references": [{ "path": "path/to/referenced-project" }]
}

核心就是一個(gè)path屬性,該屬性指向被引用的項(xiàng)目模塊路徑,該路徑下需要包含tsconfig.json,如果該模塊不是用tsconfig.json命名的話,你也可以指定具體的文件名,比如:

{
  "references": [{ "path": "path/to/referenced-project/tsconfig.web.json" }]
}

當(dāng)指定了references選項(xiàng)后,會(huì)發(fā)生如下改變:

  • 在主模塊中導(dǎo)入被引用的模塊時(shí),會(huì)加載它的類型聲明文件,也就是.d.ts后綴的文件
  • 使用tsc --buildtsc -b構(gòu)建主模塊時(shí),會(huì)自動(dòng)構(gòu)建被引用的模塊

這樣一來能夠帶來三個(gè)好處:

  • 提升類型檢查和構(gòu)建的速度
  • 減少IDE的運(yùn)行內(nèi)存占用
  • 更容易對(duì)項(xiàng)目結(jié)構(gòu)進(jìn)行劃分

tsconfig.json 的 composite 配置項(xiàng)

光是在主模塊中指定references配置項(xiàng)還不夠,還需要在被引用的項(xiàng)目對(duì)應(yīng)的tsconfig.json中開啟composite配置項(xiàng)

composite配置項(xiàng)又是干嘛的呢? -- 它可以幫助tsc快速確定如何尋找被引用項(xiàng)目的輸出產(chǎn)物

當(dāng)被引用的項(xiàng)目開啟composite配置項(xiàng)后,會(huì)有如下改變和要求:

當(dāng)未指定rootDir時(shí),默認(rèn)值不再是The longest common path of all non-declaration input files,而是包含了tsconfig.json的目錄

Tips: 關(guān)于The longest common path of all non-declaration input files的意思可以到tsconfig.json 文章中關(guān)于 rootDir 的介紹中查閱

必須開啟include或者files配置項(xiàng)將要參與構(gòu)建的文件聲明進(jìn)來

必須開啟declaration配置項(xiàng)(因?yàn)榍懊娼榻Breferences的時(shí)候說了,會(huì)加載被引入模塊的類型聲明文件,因此被引用模塊自然得開啟declaration配置項(xiàng)生成自己的類型聲明文件供主模塊加載)

使用 Project References 改造示例項(xiàng)目

根據(jù)目前我們對(duì)Project References的認(rèn)識(shí),現(xiàn)在可以開始改造一下我們的項(xiàng)目了,首先是根目錄下的tsconfig.json配置,它起到一個(gè)類似于項(xiàng)目入口的作用,因此這里面只負(fù)責(zé)添加references聲明項(xiàng)目中需要被構(gòu)建的模塊,以及通過exclude將不需要參與構(gòu)建的模塊排除(比如src/__test__中的測(cè)試代碼)

/tsconfig.json

{
  "references": [
    { "path": "src/client" },
    { "path": "src/server" },
    { "path": "src/shared" }
  ],
  "exclude": ["**/__test__"]
}

然后是各個(gè)子模塊的tsconfig.json配置,這里我們假設(shè)構(gòu)建目標(biāo)為es5的代碼,所以對(duì)于client、server以及shared來說是存在公共配置的,所以我們可以抽離出一個(gè)公共配置,然后在子模塊中通過extends配置項(xiàng)公用一個(gè)配置

/tsconfig.base.json

{
  "compilerOptions": {
    "target": "ES5",
    "module": "CommonJS",
    "strict": true
  }
}

src/client/tsconfig.json

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "../../dist/client",
    "composite": true,
    "declaration": true
  },
  // 依賴哪個(gè)模塊則引用哪個(gè)模塊
  "references": [{ "path": "../shared" }]
}

src/server/tsconfig.json

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "../../dist/server",
    "composite": true,
    "declaration": true
  },
  // 依賴哪個(gè)模塊則引用哪個(gè)模塊
  "references": [{ "path": "../shared" }]
}

src/shared/tsconfig.json

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "../../dist/shared",
    "composite": true,
    "declaration": true
  }
}

全量構(gòu)建

現(xiàn)在我們?cè)陧?xiàng)目根目錄下運(yùn)行tsc --build --verbose,就會(huì)根據(jù)references配置去尋找各個(gè)子模塊,并對(duì)它們進(jìn)行構(gòu)建,可以理解為對(duì)項(xiàng)目的全量構(gòu)建

--build 參數(shù)表示讓tscbuild模式進(jìn)行構(gòu)建和類型檢查,也就是會(huì)使用references配置項(xiàng),如果不開啟的話是不會(huì)使用references配置項(xiàng)的,這點(diǎn)可以從官方文檔中得證:

--verbose 參數(shù)則是會(huì)將構(gòu)建過程中的輸出顯示在控制臺(tái)中,不開啟該參數(shù)的話則不會(huì)顯示輸出(除非構(gòu)建過程中報(bào)錯(cuò))

運(yùn)行后/dist目錄結(jié)構(gòu)如下

dist
├── client
│   ├── index.d.ts
│   ├── index.js
│   └── tsconfig.tsbuildinfo
├── server
│   ├── index.d.ts
│   ├── index.js
│   └── tsconfig.tsbuildinfo
└── shared
    ├── index.d.ts
    ├── index.js
    └── tsconfig.tsbuildinfo

可以看到,所有子模塊都被構(gòu)建進(jìn)來了,各模塊的產(chǎn)物中有一個(gè)tsconfig.tsbuildinfo文件,這個(gè)文件起到一個(gè)類似緩存的作用,對(duì)于后續(xù)進(jìn)行增量構(gòu)建有著重要作用

前面看到的官方文檔中對(duì)tsc --build的作用的介紹中的第二點(diǎn)Detect if they are up-to-date主要就是依靠這個(gè)緩存文件去識(shí)別的

開啟--verbose參數(shù)后,可以看到控制臺(tái)輸出如下:

[4:50:26 PM] Projects in this build:
    * src/shared/tsconfig.json
    * src/client/tsconfig.json
    * src/server/tsconfig.json
    * tsconfig.json
[4:50:26 PM] Project 'src/shared/tsconfig.json' is out of date because output file 'dist/shared/tsconfig.tsbuildinfo' does not exist
[4:50:26 PM] Building project '/home/plasticine/demo/ts-reference-demo/src/shared/tsconfig.json'...
[4:50:28 PM] Project 'src/client/tsconfig.json' is out of date because output file 'dist/client/tsconfig.tsbuildinfo' does not exist
[4:50:28 PM] Building project '/home/plasticine/demo/ts-reference-demo/src/client/tsconfig.json'...
[4:50:28 PM] Project 'src/server/tsconfig.json' is out of date because output file 'dist/server/tsconfig.tsbuildinfo' does not exist
[4:50:28 PM] Building project '/home/plasticine/demo/ts-reference-demo/src/server/tsconfig.json'...
[4:50:29 PM] Project 'tsconfig.json' is out of date because output 'src/shared/index.js' is older than input 'src/client'
[4:50:29 PM] Building project '/home/plasticine/demo/ts-reference-demo/tsconfig.json'...
[4:50:29 PM] Updating unchanged output timestamps of project '/home/plasticine/demo/ts-reference-demo/tsconfig.json'...

xxx out of date xxx意思就是這個(gè)模塊沒被構(gòu)建過,因此會(huì)開始對(duì)其進(jìn)行構(gòu)建

由于我們是首次構(gòu)建,所以三個(gè)模塊都是沒被構(gòu)建過的,所以三個(gè)模塊都被檢測(cè)為out of date

當(dāng)我們?cè)俅芜\(yùn)行tsc --build --verbose時(shí),輸出如下:

4:54:35 PM - Projects in this build:
    * src/shared/tsconfig.json
    * src/client/tsconfig.json
    * src/server/tsconfig.json
    * tsconfig.json
4:54:35 PM - Project 'src/shared/tsconfig.json' is up to date because newest input 'src/shared/index.ts' is older than output 'dist/shared/tsconfig.tsbuildinfo'
4:54:35 PM - Project 'src/client/tsconfig.json' is up to date because newest input 'src/client/index.ts' is older than output 'dist/client/tsconfig.tsbuildinfo'
4:54:35 PM - Project 'src/server/tsconfig.json' is up to date because newest input 'src/server/index.ts' is older than output 'dist/server/tsconfig.tsbuildinfo'
4:54:35 PM - Project 'tsconfig.json' is up to date because newest input 'dist/server/index.d.ts' is older than output 'src/client/index.js'

可以看到,所有模塊都被檢測(cè)為up to date,從而避免了重復(fù)構(gòu)建

增量構(gòu)建

如果現(xiàn)在我們修改了client模塊的代碼,再運(yùn)行tsc --build --verbose會(huì)怎樣呢?估計(jì)你也能猜到了,只有client模塊會(huì)被構(gòu)建,而其他模塊則會(huì)跳過

4:56:44 PM - Projects in this build:
    * src/shared/tsconfig.json
    * src/client/tsconfig.json
    * src/server/tsconfig.json
    * tsconfig.json
4:56:44 PM - Project 'src/shared/tsconfig.json' is up to date because newest input 'src/shared/index.ts' is older than output 'dist/shared/tsconfig.tsbuildinfo'
4:56:44 PM - Project 'src/client/tsconfig.json' is out of date because output 'dist/client/tsconfig.tsbuildinfo' is older than input 'src/client/index.ts'
4:56:44 PM - Building project '/home/plasticine/demo/ts-reference-demo/src/client/tsconfig.json'...
4:56:45 PM - Project 'src/server/tsconfig.json' is up to date because newest input 'src/server/index.ts' is older than output 'dist/server/tsconfig.tsbuildinfo'
4:56:45 PM - Project 'tsconfig.json' is out of date because output file 'src/client/index.js' does not exist
4:56:45 PM - Building project '/home/plasticine/demo/ts-reference-demo/tsconfig.json'...
4:56:45 PM - Updating unchanged output timestamps of project '/home/plasticine/demo/ts-reference-demo/tsconfig.json'...

相信現(xiàn)在你能體會(huì)到Project References的好處了吧,能夠很大程度上優(yōu)化我們的構(gòu)建速度!

不過實(shí)際開發(fā)中,tsc更多的是用來進(jìn)行類型檢查,至于compile的工作,則更多地是交給如Babel、swc、esbuild等工具去完成,這也是官方文檔中有提到過的

這也是為什么你在vite創(chuàng)建的項(xiàng)目中能夠看到默認(rèn)的build命令配置為tsc && vite build,正是將類型檢查的工作交給tsc,而構(gòu)建工作則交給vite底層依賴的rollup去完成

對(duì)__test__測(cè)試代碼的處理

我們的改造貌似已經(jīng)完成了,但其實(shí)還忽略了一個(gè)src/__test__,它也可以被視為一個(gè)模塊,它作為主模塊,依賴了clientserver,因此也可以給它加上tsconfig.json配置,并且對(duì)于測(cè)試代碼,我們一般不希望將它們構(gòu)建成js,只希望tsc負(fù)責(zé)類型檢查的工作,因此我們需要進(jìn)行如下配置:

src/__test__/tsconfig.json

{
  "compilerOptions": {
    "noEmit": true
  },
  "references": [{ "path": "../client" }, { "path": "../server" }]
}

noEmit的作用剛剛在官方文檔中也看到了,不會(huì)把產(chǎn)物文件輸出,如果我們只需要類型檢查能力的話很適合開啟該配置項(xiàng)

現(xiàn)在我們?nèi)绻枰獙?duì)__test__中的代碼進(jìn)行類型檢查的話,只需要執(zhí)行:

# 忽略 references 配置項(xiàng)
tsc --project src/__test__
# 啟用 references 配置項(xiàng)
tsc --build src/__test__

如果是使用--project參數(shù)的話,tsconfig.json中可以忽略references配置項(xiàng),因?yàn)榧幢闩渲昧艘膊粫?huì)被使用,這在依賴產(chǎn)物未構(gòu)建出來時(shí)能起作用

而如果使用--build參數(shù),并且clientserver未構(gòu)建出來時(shí),會(huì)先構(gòu)建它們,再對(duì)測(cè)試代碼進(jìn)行類型檢查,可以根據(jù)個(gè)人需求場(chǎng)景來決定使用--project還是--build

總結(jié)

本篇文章介紹了Project References是什么,并通過一個(gè)簡(jiǎn)單的示例項(xiàng)目,并結(jié)合TypeScript Documentation官方文檔邊實(shí)戰(zhàn)邊解釋

總的來說,其使用起來就是:

  • 主模塊(tsc --build作用的模塊視為主模塊)中通過references配置項(xiàng)聲明依賴的模塊
  • 被引用模塊中開啟compositedeclaration配置項(xiàng)以支持被引用
  • 通過tsc --build 主模塊才可以啟用references配置項(xiàng),這在官方文檔中被稱為Build Mode,如果直接tsc 主模塊的話,是不會(huì)啟用references配置項(xiàng)的,也就導(dǎo)致依然會(huì)對(duì)項(xiàng)目中的所有ts文件進(jìn)行編譯(如果沒配置includefiles配置項(xiàng)的話)

希望通過本篇文章,能夠讓你對(duì)Project References有一個(gè)全面了解,也希望能夠?qū)⑵溆迷谀愕捻?xiàng)目中,提升類型檢查或構(gòu)建(使用 tsc 進(jìn)行構(gòu)建的話)的速度,更多關(guān)于tsc性能Project References的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論