最近在工作中,我們決定遷移到命名導出/導入並添加 eslint 規則 no-default-export。
動機聽起來是這樣的:
預設匯出會使程式碼更難維護,尤其是在大型程式碼庫中。對於相同實體,導入的名稱可能不同,影響程式碼讀取過程和編寫靜態分析器,增加難度。相反,切換到命名導出可以消除預設導出的所有缺點。
當然,我們有龐大的程式碼庫,手動替換 ~1500 個預設匯出和 ~12000 個預設導入並不是一項有趣的工作?
主要困難是使用為命名匯出建立的相同新識別碼更新所有連結檔案。
我舉個例子給你聽:
// Button/Button.tsx const Button = () => {}; export default Button; // Button/index.ts export { default } from './Button.tsx'; // SomePage1.tsx import OldButton from './component/Button'; // SomePage2.tsx import TestButton from './component/Button';
我假設的目標結果如下:
// Button/Button.tsx export const Button = () => {}; // Button/index.ts export { Button } from './Button.tsx'; // SomePage1.tsx import { Button as OldButton } from './component/Button'; // SomePage2.tsx import { Button as TestButton } from './component/Button';
我在網路上找到的每個解決方案都只是一個程式碼模組,用於獨立轉換每個文件,而不知道該文件以外的任何其他內容。
我開始夢想有一個解析器能夠:
- 解析專案中的所有匯入並儲存檔案之間的關係
- 收集有關預設導入/匯出的資訊
- 為命名匯出建立新的識別碼名稱
- 替換儲存庫中的所有條目?
因此,我接受了新的挑戰,開發了一個 codemod 工具,可以自動將預設匯出/匯入重寫為命名的匯出/匯入。
我已經開發出來了! ? ? 劇透
開發流程
第一個想法
它發生在我之前的實驗可視化反應組件樹之後,第一個想法是重用babel 和webpack 插件來迭代所有模組並解析AST,但是為什麼,如果jscodeshift 已經有了解析器,並且如果我找到了替代品webpack插件我將能夠編寫一個與捆綁器無關的工具,這很棒嗎?
工具
好的,我有一個 jscodeshift 作為解析器。但是為了找到從入口點開始的所有檔案之間的關係,我找到了resolve包,它有助於解析像原生nodejs require.resolve這樣的路徑,但它更類似於解析像bundlers這樣的路徑,你可以更好地控制擴展,同步/異步行為等
設計兩步驟流程
我的工具的初始版本就像一個腳本中的所有內容。然而,為了提高靈活性和效能,並透過調試簡化開發過程,我將該工具重構為兩個階段:
-
資料收集:第一階段收集程式碼庫中預設導入和匯出的所有實例
- 我引入了一個環境變數 IS_GATHER_INFO 來控制這個階段。腳本使用resolve來尋找預設匯出/匯入的每個用法
- 另一個環境變數 ENTRY 包含程式碼庫入口點的相對路徑,從該檔案開始,所有導入都會被解析和分析
-
轉換:收集資料後,第二階段將預設導出重寫為命名導出。使用 jscodeshift,我可以輕鬆地並行轉換原始程式碼。
- 我引入了一個環境變數 IS_TRANSFORM 來控制這個階段
分為以下兩個步驟:
- 我能夠將資料收集與轉換分離,減少開發和偵錯期間執行的程式碼量和花費的時間
- 這是查看 GatherInfo 函數的結果、分析它、重新運行程式碼的非常方便的方法
- 測試轉換,無需重複運行整個管道並收集數據
- 如果您需要針對不同的入口點執行此工具但重複使用收集的資料 ,收集資料轉儲會很有幫助
隨著案例開始累積(例如動態導入、重新導出預設值、不同的導出實體:變數、函數和類別以及已使用的變數問題名稱),我花了更多的時間來設定測試案例。在大約 30 分鐘內,我有了一個可靠的測試設置,使我能夠轉向測試驅動開發(TDD)
。相信我,花時間在 TDD 上這些工具是值得的,因為它們有大量的案例。您走得越遠,您從測試案例中感受到的價值就越大。我想說的是,在覆蓋了一半的情況後,如果你沒有測試,在一個巨大的項目上運行和調試將成為一場噩夢,因為每次你需要添加一些更改,它可能會破壞很多其他情況。
AST:
-
ImportDefaultSpecifier 僅查找導入預設語句
- 從「...」導入一些內容
-
ExportDefaultDeclaration 僅尋找匯出預設語句
- 導出預設的東西;
-
ExportNamedDeclaration 用於尋找導入預設值和匯出預設值語句
- 從 '...' 匯出 { 預設值 } - 預設導出
- 從 '...' 匯出 { default as Something } - 預設導入
- export { default } from '...' - 同時預設導入和預設導出
-
ImportExpression 尋找動態匯入並根據需要標記該檔案以保留預設匯出。有些工具(例如 React.lazy)僅適用於預設導出。
- 導入('...')
- 此外,我保存了有關代理文件的信息,它是導入預設內容並將該內容導出為預設內容的文件
- 用它來找出任何檔案中指定匯出的新名稱:file a ->檔案b->檔案 c
技術注意事項與已知限制
儘管該工具可以正常運行,但仍有一些邊緣情況尚未處理:
命名空間.預設用法
以下程式碼還不會被轉換:
// Button/Button.tsx const Button = () => {}; export default Button; // Button/index.ts export { default } from './Button.tsx'; // SomePage1.tsx import OldButton from './component/Button'; // SomePage2.tsx import TestButton from './component/Button';
代理文件中的衝突
來源:
// Button/Button.tsx export const Button = () => {}; // Button/index.ts export { Button } from './Button.tsx'; // SomePage1.tsx import { Button as OldButton } from './component/Button'; // SomePage2.tsx import { Button as TestButton } from './component/Button';
結果:
import * as allConst from './const'; console.log(allConst.default);
混亂的匯出,例如
來源:
export { Modals as default } from './Modals'; export { Modals } from './Modals';
將導致邏輯損壞,因為現在它有兩個具有不同實現的相同導出:
export { Modals } from './Modals'; export { Modals } from './Modals';
前一個實體的導入也應該手動修復
來源:
export class GhostDataProvider {} export default hoc()(GhostDataProvider);
結果:
export class GhostDataProvider {} const GhostDataProviderAlias = hoc()(GhostDataProvider); export { GhostDataProviderAlias as GhostDataProvider };
儘管有這些限制,我還是在 15-20 分鐘內手動修復了其餘錯誤,並成功啟動了我們的真實專案。重寫預設導出。
連結
- jscodeshift
- astexplorer
就是這樣,歡迎下方留言! ?
以上是建置用於重寫預設導出的 Codemod 工具的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript核心數據類型在瀏覽器和Node.js中一致,但處理方式和額外類型有所不同。 1)全局對像在瀏覽器中為window,在Node.js中為global。 2)Node.js獨有Buffer對象,用於處理二進制數據。 3)性能和時間處理在兩者間也有差異,需根據環境調整代碼。

JavaScriptusestwotypesofcomments:single-line(//)andmulti-line(//).1)Use//forquicknotesorsingle-lineexplanations.2)Use//forlongerexplanationsorcommentingoutblocksofcode.Commentsshouldexplainthe'why',notthe'what',andbeplacedabovetherelevantcodeforclari

Python和JavaScript的主要區別在於類型系統和應用場景。 1.Python使用動態類型,適合科學計算和數據分析。 2.JavaScript採用弱類型,廣泛用於前端和全棧開發。兩者在異步編程和性能優化上各有優勢,選擇時應根據項目需求決定。

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

SublimeText3漢化版
中文版,非常好用