首頁/ 遊戲/ 正文

我們將40萬行程式碼從Flow遷移到了TypeScript

【CSDN 編者按】哪種型別系統將主宰JavaScript的世界?不同時代有不同的答案。本文作者在選擇Web生態系統用於構建的產品Factorial時,對比當時facebook的Flow和微軟的TypeScript,綜合考慮選擇了略勝一籌的Flow。但隨著時間的推移,TypeScript開始在該領域展現主導地位。於是決定換框架,來看看他們是怎麼做的吧。

原文連結:

https://labs。factorialhr。com/posts/how-we-migrated-400k-lines-of-code-from-flow-to-typescript

作者 | Ferran Basora

譯者 | 彎月  責編 | 章雨銘

出品 | CSDN(ID:CSDNnews)

在構建我們的產品Factorial之際,Web生態系統正在經歷一場激戰:哪種型別系統將主宰JavaScript的世界。兩大主要競爭者分別是來自Facebook的Flow和來自微軟的TypeScript。就功能而言,這兩大框架似乎並沒有太大區別,只不過Flow支援async/await和裝飾器等不錯的功能,所以略勝一籌。更不用說它與React都出自Facebook之手,因此在當時,它與React配合使用的效果更佳。

在Web(無論是前端還是後端)不支援型別檢查的時代,將型別系統(無論是哪一種)新增到最小可行產品成為了程式碼質量和維護方面的及格線。最後,我們還是選擇了Flow。

隨著時間的推移,TypeScript開始在該領域展現出主導地位。TypeScript的發展更快、社群更大、擁有大量的型別庫、擁有更好的外掛和IDE支援,以及許多其他優勢,例如在npm生態系統中的廣泛採用,因此許多擁有型別的庫都得以公開。

另一方面,我們深受Flow檢查器無休止的分析和記憶體洩漏方面的折磨,儘管TypeScript檢查器在效能方面的表現也差強人意,但它在配置方面的粒度與各

種標誌確實非常吸引人。於是,我們決定換框架。

我們將40萬行程式碼從Flow遷移到了TypeScript

遷移的注意事項

在遷移方法的初步審查期間,為了確保遷移成功,我們列出了一組必須遵守的約束,其中包括:

不能凍結程式碼。

想象一下告訴開發團隊:“我們要開始遷移大量的程式碼了,持續時間還不確定,你可不可以暫停一下手頭的工作……”不太現實吧?停止開發會給專案帶來太多風險。

保留 Git 歷史記錄

原始碼的資訊遠不止程式碼本身,還有每一行程式碼背後的歷史記錄。如果在程式碼遷移到過程中,這些歷史記錄丟失,就太可惜了。

進行最終的遷移時,最好不要干擾現有的拉取請求

。我們不希望程式碼遷移引發大量拉取請求方面的衝突和各種麻煩。

不能造成思維模式的混亂。

許多教程在介紹JavaScript檔案中使用TypeScript的功能時,都採用了漸進式的遷移過程。但是,我們不希望團隊在思維模式方面出現混亂,即不知道在某個時間點使用哪種技術,並導致無法判斷遷移何時結束。

這些約束並非晦澀難懂,但是我們會竭盡所能遵守這些約束,並找出遷移需要面對的長期挑戰。

我們將40萬行程式碼從Flow遷移到了TypeScript

左右為難

在開始遷移程式碼之前,我們首先研究了其他團隊,他們也面臨著相同的挑戰:將龐大的程式碼庫從Flow(或JavaScript)遷移到TypeScript。我們做了很多研究,並在動手遷移程式碼之前總結了一些經驗。

在程式碼遷移的策略方面,我們有兩個選擇:

方法A:將大部分程式碼庫都遷移過去,以儘可能減少思維模式混亂的問題。這就需要漸進式遷移,所以我們選擇從沒有依賴關係的資料夾開始下手。

方法B:建立一個“一次性”指令碼來遷移整個程式碼庫。透過這種方法正確遷移程式碼的難度非常大,因為我們需要將Flow的每一行程式碼都自動地轉換成TypeScript。

最後,我們決定混合使用這兩種方法(吸取兩家之長)。我們發現,程式碼庫中有一大塊程式碼與其他檔案之間是解耦的,很適合作為遷移的首個目標,並驗證在生產中使用Typescript的想法。令人驚訝的是,我們率先遷移了這部分程式碼,併成功交付了。我們證明了Flow和TypeScript可以並存。因此,我們對一次性交付其餘原始碼的信心大增。

我們將40萬行程式碼從Flow遷移到了TypeScript

另一個困境:工具

Ts-migrate:這是我們找到的最出色的工具之一,來自Airbnb,它可以自動遷移JavaScript程式碼庫,同時根據TypeScript語言伺服器的輸出來決定如何處理不符合規範的地方。但我們沒有采用這種方式,因為我們需要將程式碼從Flow遷移到TypeScript,而不是從JavaScript到TypeScript,二者完全沒有可比性。

Flow-to-ts:這是我們此次程式碼遷移採用的主要工具之一,來自可汗學院。該工具是此次遷移的基礎,我們對這款工具充滿了感激。稍後我們會進一步討論為何當初選擇了它。

我們將40萬行程式碼從Flow遷移到了TypeScript

開始遷移

為了遵守上面提到的首要約束(避免程式碼凍結),我們想方設法將盡可能多地將安全程式碼合併到主分支中。所謂“安全程式碼”指的是將TypeScript的配置檔案、輸入定義等推送到程式碼庫。

另一方面,我們在一個分支中寫了一個bash指令碼,其中包含了遷移的所有步驟。以下是該指令碼中包含的遷移步驟:

執行一組自定義的JsCodeShift轉換;

在Git上,將所有js和jsx檔案重新命名為ts和tsx;

針對上述所有程式碼執行flow-to-ts轉換;

執行lint和格式化工具,檢查格式;

執行tsc驗證並檢視不符合規範的地方。

自定義JsCodeShift轉換

考慮到上述步驟,我們決定不斷迭代,以逐步減少tsc檢測出的規範違反的程式碼。對於所有重複出現的規範違反,我們嘗試編寫了一些JSCodeShift轉換。我們大量使用ASTExplorer作為實驗場所,來編寫我們的自定義轉換。由於我們的程式碼庫是Flow,所以我們決定利用這個先天優勢,自動調整與型別相關的程式碼,以簡化flow-to-ts的轉換。

在這一步中,我們編寫了十多個自定義轉換,然後同時執行所有轉換。

module。exports = function (file, api, options) {

const

fixes = [

transformation1,

transformation2,

transformation3,

。。。

return

fixes。reduce(

src, fix

) =>

{

if

typeof

src ===

‘undefined’

) {

return

}

return

fix({ 。。。file,

source

: src }, api, options)

}, file。source)

}

Git 重新命名

根據bash指令碼,下一步是檔案的重新命名。我們使用了git mv,儘可能保持Git歷史記錄:

find

$@

-iname

“*。js”

|

while

read

line;

do

git mv ——

$line

${line%。js}

。ts;

done

find

$@

-iname

“*。jsx”

|

while

read

line;

do

git mv ——

$line

${line%。jsx}

。tsx;

done

這一步的工作很簡單,很容易被忽略,但從長遠來看卻非常重要。

執行 flow-to-ts

在這一步中,指令碼需要使用flow-to-ts包執行主要的轉換。flow-to-ts是Flow專案的一個核心工具,它理解許多Flow的常見模式,這些模式可以確定地對映到Typescript。它的內部是一個巨大的 JSCodeShift 轉換,但有一些預設的配置可以讓該工具的使用更容易。

Lint和格式化

儘管flow-to-ts的底層使用了recast ,而且會盡可能地保留程式碼原來的格式,但在轉換到過程中會新建一些程式碼。這些程式碼需要格式化,以匹配我們的內部規則。

這一步有點慢,但不可略過。儘可能保持程式碼原來的格式對於保留Git歷史記錄至關重要。

使用tsc進行驗證和審查

有了這個指令碼,完成遷移到最後一步就是解決其他非重複性的規則違反。老實說,這是最困難的一部分工作,因為我們必須逐一排查並解決。在這個過程中,由於程式碼庫是Flow,所以我們可以不斷地將型別修復推送到master分支,同時還不會影響到應用程式的行為。

我們將40萬行程式碼從Flow遷移到了TypeScript

總結成功的經驗

我們成功了!我們一次性將40萬行程式碼從Flow遷移到了TypeScript!在這個過程中,我們積累了很多寶貴的經驗。

保持透明,持續溝通,以獲得團隊的支援。最糟糕的情況是,在沒有取得每一位團隊成員支援的情況下,開展大量的工作。我們建議,分享、參與和記錄遷移的每一個步驟、里程碑和關鍵日期。

在開始動手遷移程式碼之前,做好準備。這是一個漫長的過程,需要深入瞭解程式碼庫。你可能會發現,為了完成最後一步的遷移,前面的有些步驟需要返工。舉個例子,我們發現裝飾器的使用會影響flow-to-ts的執行。

仔細思考遷移後代碼的情況,並提出正確的問題。遷移後的所有工具都準備好了嗎?開放的拉取請求會影響遷移嗎?遷移後是否會出現lint和格式的問題?我們在合併程式碼之前,就已經解決了這些問題。

最好將所有與遷移相關的提交壓縮為一個提交。這可以簡化部署,如果出現意外情況,也很方便回滾。

我們將40萬行程式碼從Flow遷移到了TypeScript

今後的打算

我們的TypeScript之旅並沒有就此結束。事實上,這只是一個開始!在採用該語言幾天後,我們決定啟用編譯器中的strict標誌。對我們來說幸運的是,我們可以逐步完成這項工作,因為這些標誌可以一個個新增。

此外,我們也在考慮其他工具和機會。例如,目前我們使用Webpack來構建應用程式,但我們已經開始考慮esbuild和swc,因為這兩個編譯器對 TypeScript的支援更好。

幾個月前,我們也惴惴不安,不知道能否在前端程式碼庫中使用TypeScript。我們分析了利弊,併為此次大規模的程式碼遷移制定了明確的計劃。兩週後的今天,我們團隊實現了更快的交付,而且還大幅提高了程式碼質量。這不僅可以減少生產中的錯誤,而且還可以讓客戶更滿意。

如果你也面臨相同的困境,希望這篇文章對你有所幫助。

相關文章

頂部