動態

詳情 返回 返回

通過 AST 實現組件庫替換升級 - 動態 詳情

年初接到一個任務將 semi-ui 替換到 antd,但是能人力預算不太夠,所以基於工作量和效率選擇了基於 AST 的替換方案。

項目技術棧是 React + tsx

為什麼要使用 AST?

AST(Abstract Syntax Tree,抽象語法樹)是一種在計算機科學中表示源代碼語法結構的樹狀數據結構
通過 AST,可以理解代碼的結構和含義,實現代碼分析、轉換和操作
基於 AST 的替換方案可以快速而準確的對大量代碼進行修改,提高開發效率和代碼質量。

還有什麼方案?

  1. 固定字符串替換。對於 import 和 tsx 都有嚴重的誤傷。
  2. 正則替換,編寫複雜,嵌套難以識別。
  3. 手動替換,重複性工作容易失誤,耗費工時太多,適合小工作量的情況。

方案比對

方案 工作量 誤傷 import 組件替換 組件屬性替換
固定字符串替換 😭 😭 😒 😒
正則 😒 😭 😒 😒 😒
手動 😭
AST

Babel 簡介

Babel 是前端領域的必備工具,是一種源碼到源碼的轉譯器。
在項目中可以讓我們使用一些新的語法(展開運算符) 和 api(@babel/core),會在編譯的過程中將 code 轉為目標環境所支持的語法並引入 polyfill

Babel 實際應用場景

  1. ()=>{} 轉為 function(){}
  2. Array.isArray 添加 polyfill

除了上面提到的編譯轉譯代碼之外,babel 也可以用來做靜態分析,分析代碼提取信息,然後生成文檔
如:

  1. 自動國際化處理
  2. Linter
  3. 壓縮混淆,刪除死代碼,變量名混淆。
  4. 模塊遍歷器,分析 import 移除未被使用的資源模塊

Babel 編譯原理

babel 是 source to source 的轉換,整體編譯流程分為三步:
• parse:通過 parser 把源碼轉成抽象語法樹(AST)
• transform:遍歷 AST,調⽤各種 transform 插件對 AST 進⾏增刪改
• generate:把轉換後的 AST 打印成⽬標代碼,並⽣成 sourcemap

Babel 中常⻅節點

  1. Literal 是字⾯量的意思,比如説 'are you sure?'
  2. Statement 是語句
  3. Identifer 是標識符的意思
  4. Declaration 聲明語句是⼀種特殊的語句,它執⾏的邏輯是在作⽤域內聲明⼀個變量、函數、class、import、export 等。
  5. Expression 是表達式,特點是執⾏完以後有返回值,這是和語句 (statement) 的區別。
  6. Element 是 JSX,分為 JSXElement、JSXOpeningElement、JSXClosingElement 等等

image.png

Babel 中常⽤ API

  1. @babel/parser :babel parser 叫 babylon,是基於 acorn 實現的,擴展了很多語法,可以⽀
    持 es next(現 在⽀持到 es2020)、jsx、flow、typescript 等語法的解析。babel parser 默認只
    能 parse js 代碼,jsx、flow、typescript 這些⾮標準的語法的解析需要指定語法插件。
  2. @babel/traverse :parse 出的 AST 由 @babel/traverse 來遍歷和修改,⽀持指定要遍
    歷的 AST 節點,指定 visitor 函數。babel 會在遍歷 parent 對應的 AST 時調⽤相應的 visitor 函
  3. 數。@babel/types :遍歷 AST 的過程中需要創建⼀些 AST 和判斷 AST 的類型,這時候就需要
    @babel/types 包。t.isIfStatement 創建,t.assertIfStatement ⽤於判斷。
  4. @babel/template :⽀持通過代碼來⽣成 ast 進⾏替換。相⽐ parser ,template ⽀持不同粒
  5. @babel/generator :AST 轉換完之後就要打印成⽬標代碼字符串,通過
    @babel/generator 包
  6. @babel/helper-module-imports

替換實戰

存在的問題

  1. 項⽬技術棧 React + tsx
  2. 839 個⽂件中,使⽤ 63 個組件,共計 2485 次使⽤,最多⼀個組件被使⽤了 299 次。
  3. 項⽬周⼀、週三四,上線時間不定。更新頻率較⾼
  4. 沒有測試同學,研發⾃測。測試環境⾃測,⽆等待時間,即可上線

實戰腳本

替換屬性值&替換屬性名

  1. Space 不⽀持 vertical 需要改為 direction="vertical"
  2. 替換 onChange 事件調⽤
  3. 提取 children 構建為 options
  4. 替換 Size 改為新的映射關係
  5. 將 Link 解構賦值

整體⽅案

  1. 統計待升級組件,確認替換範圍和影響(839 個⽂件中,使⽤ 63 個組件,共計 2485 次使⽤)
  2. 項⽬格式化 npx eslint --fix ./src , prettier --write '*/.{tsx,ts}' , 暫
    不開啓編輯器⾃動格式化
  3. 分批替換(⻚⾯維度、組件維度)每週替換4個組件,以低頻⾼優作為參考項。
  4. 與業務⽅溝通確定上線節奏及變更影響範圍,周⼆推 test,週四推 online,提前⼀周在業務羣公佈。替換計劃固定變更影響範圍。
  5. 測試驗收(⾃測&test環境)功能、樣式
  6. ⽀持快速回滾。依賴 turbo 實現快速回滾,採⽤臨時 release 分⽀,實現需求迭代和組件替換不衝突,遇到問題也可以快速回滾。
  7. 加⼊業務 feedback 羣,遇到問題優先回滾⽌損。
  8. 所有替換⼯作完成後,開啓⾃動格式化,移除⽆效代碼。

優缺點&改進

優點:
• ⽀持增量替換,不阻塞業務開發
• ⽀持快速回滾
• 適合⼤批量重複性⼯作
• 適合 jsx 這種嵌套關係的內容修改,可以減少誤傷

缺點:
• 有⼀定的學習成本(當然可以使⽤ GitHub Copilot 、ChatGpt 減少⼀些⼯作量),
• 需要收集組件差異(這⾥可以考慮提取屬性和⽅法,然後抓取⽂檔中的定義做⽐對)
• 編碼成本(如果替換數量不多,可以考慮⼿動替換)

總結

最後我們再來回顧⼀下 @babel/parser 、 @babel/traverse 、 @babel/types 、
@babel/template 、 @babel/generator 這些庫的作⽤。

也可以想想有什麼應⽤場景是可以落地的?⽐如説
• ⾃動國際化,通過腳本提取所有⽂案。
• 增加⼀些個性化的格式化規則,⾃閉合標籤,優化 imoprt 導⼊順序。

傳送⻔

  1. Babel 插件通關秘籍 - zxg_神説要有光 - 掘⾦⼩冊
  2. https://astexplorer.net/
  3. Stackblitz 測試地址:Express Starter - StackBlitz
user avatar toopoo 頭像 dingtongya 頭像 Leesz 頭像 linlinma 頭像 front_yue 頭像 kobe_fans_zxc 頭像 aqiongbei 頭像 chongdianqishi 頭像 longlong688 頭像 u_17443142 頭像 zero_dev 頭像 shuirong1997 頭像
點贊 170 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.