0成本上手AST,應(yīng)用GoGoCode解決Vue2遷移Vue3難題

1 為什么要遷移 Vue3.x

說點(diǎn)什么呢俺陋?
總之豁延。。腊状。 這不是我的錯诱咏!
首先先要寫個案例,找到一個可執(zhí)行方案缴挖。


image.png

2 方案選擇

參考Vue2轉(zhuǎn)3官方文檔
https://v3.cn.vuejs.org/guide/migration/introduction.html

面對自己項(xiàng)目百八十個文件袋狞,人工爆肝肯定是不可能的,想都不能想映屋!
唯一的方案是基于AST(抽象語法樹)解構(gòu)代碼苟鸯,根據(jù)Vue官網(wǎng)給出升級文檔的修改建議,批量修改輸出文件的方案棚点。
只是早处。。瘫析。AST操作有點(diǎn)復(fù)雜砌梆。

image.png

調(diào)研了幾個工具,GitHub上找到了幾個去掉代碼文件里 console.log 的示例學(xué)習(xí)學(xué)習(xí):(這兩處代碼引用作對比方案颁股,可以跳過)
一. 利用 jscodeshift 操作 AST去掉console.log 的示例:

export default (fileInfo, api) => {
  const j = api.jscodeshift;
  const root = j(fileInfo.source)
  const callExpressions = root.find(j.CallExpression, {
      callee: {
        type: 'MemberExpression',
        object: { type: 'Identifier', name: 'console' },
      },
    }
  );
  callExpressions.remove();
  return root.toSource();
};

二. 利用 babel 操作 AST去掉console.log 的示例:
(基于篇幅省略了部分代碼么库,有興趣的同學(xué)請?jiān)L問https://github.com/mattphillips/babel-plugin-console

export default function({
  types,
}: typeof BabelCore): PluginObj<ConsoleTransformState> {
  return {
    name: 'console-transform',
    visitor: {
      CallExpression(path, { opts, file }) {
        validateSchema(schema, opts);
        const { env, removeMethods, additionalStyleMethods } = opts;
        const callee = path.get('callee');       
        /*
        基于篇幅限制
        此處省略40+行代碼
        */        
      },
    },
  };
}

基于本人實(shí)力,這兩個方案實(shí)在是勸退案例甘有。


image.png

正在我為這個項(xiàng)目重構(gòu)發(fā)愁诉儒,發(fā)量迅速減少,混跡于社區(qū)尋找解救方案的時(shí)候亏掀,忽然發(fā)現(xiàn)了GoGoCode這個工具忱反。

貼一段官方介紹:

GoGoCode是一個操作AST的工具泛释,可以降低使用AST的門檻,幫助開發(fā)者從繁瑣的AST操作中解放出來温算,更專注于代碼分析轉(zhuǎn)換邏輯的開發(fā)怜校。簡單的替換甚至不用學(xué)習(xí)AST,而初步學(xué)習(xí)了AST節(jié)點(diǎn)結(jié)構(gòu)(可參考AST查看器)后就可以完成更復(fù)雜的分析轉(zhuǎn)換注竿。

GoGoCode的官方文檔 https://gogocode.io/zh/docs/specification/getting-started

這不正是我想要的么茄茁,遇到你就是古話說的,瞌睡來了有人遞枕頭巩割!
而GoGoCode操作 AST 去掉 代碼中console.log裙顽,僅僅只需要一行代碼!宣谈!

$(`要轉(zhuǎn)換的代碼段`).find(`console.log($_$)`).remove()

熟悉的 $符號愈犹,熟悉的find、remove等API闻丑,扣一下題漩怎,說零成本操作AST不算標(biāo)題黨吧
爆贊!`挛恕勋锤!方案選定!K崆铡怪得!

image.png

3 開工

舉個栗子:按鍵修飾符的遷移方案

Vue2轉(zhuǎn)3官方文檔 - 按鍵修飾符的遷移
https://v3.cn.vuejs.org/guide/migration/keycode-modifiers.html#%E6%A6%82%E8%A7%88

以下是變更的簡要總結(jié):

  • 非兼容:不再支持使用數(shù)字 (即鍵碼) 作為v-on修飾符
  • 非兼容:不再支持config.keyCodes

按照文檔寫一個待轉(zhuǎn)化的Demo

<template>
 <div>
   <h1>遷移:按鍵修飾符</h1>
   <p>遷移策略:
         1.Vue3不再支持使用數(shù)字 (即鍵碼) 作為 v-on 修飾符 
         2.不再支持 config.keyCodes</p>
   <div class="mt20 text-left">
     <div>space:<input type="text" @keyup.space="keys('space')" /></div>
     <div>space:<input type="text" @keyup.32="keys('keycode 32 space')" /> </div>
     <div>space:<input type="text" @keyup.customSpace="keys('keycode 32 space')" /> </div>
   </div>
 </div>
</template>
<script>
import Vue from 'vue';
Vue.config.keyCodes = {
    customSpace: 32,
    customDelete: 46
};
export default {
  name: '按鍵修飾符', 
  methods: {
    keys(key) {
      alert('您按下的是' + key);
    },
  },
};
</script>

任務(wù)確定

根據(jù)https://astexplorer.net分析下要轉(zhuǎn)換的內(nèi)容
安利一下astexplorer.net這個工具,我們可以利用它很方便的查看某段代碼的AST語法樹結(jié)構(gòu)

image.png

這里要做的有三件事:
1)提取代碼里自定義的keyCodes(上圖藍(lán)框Vue.config.keyCodes的內(nèi)容部分)卑硫,與系統(tǒng)keyCodes合并為一個map,后續(xù)要在template替換時(shí)使用蚕断;
2)移除Vue.config.keyCodes 代碼(Vue3不再支持)欢伏;
3)遍歷所有標(biāo)簽以及它的屬性,使用合并后的keyCodes替換標(biāo)簽(上圖紅框 xx.32與xx.customSpace部分)亿乳。

轉(zhuǎn)換邏輯編寫

1.項(xiàng)目里運(yùn)行安裝GoGoCode

npm install gogocode
  1. 初始化script的AST對象
const $ = require('gogocode');
//script代碼,用$轉(zhuǎn)為AST節(jié)點(diǎn)
let scriptAst = $(`
import Vue from 'vue';
Vue.config.keyCodes = {
    customSpace: 32,
    customDelete: 46
};
export default {
  name: '按鍵修飾符',  
  methods: {
    keys(key) {
      alert('您按下的是' + key);
    },
  },
};`)

3.我們要尋找script里自定義的keyCodes(Vue.config.keyCodes的內(nèi)容部分)
使用GoGoCode的find API硝拧,加上匹配通配符_,拿到所有的自定義keyCode數(shù)組

// 匹配取出自定義的keyCode葛假,結(jié)果:Node數(shù)組
const customKeyCodeList = scriptAst.find(`Vue.config.keyCodes = {$_$}`).match[0]

這里要注意構(gòu)造匹配的 Vue.config.keyCodes = {_} 的字符串障陶,需要符合可轉(zhuǎn)AST節(jié)點(diǎn)的規(guī)范
可以拿到 astexplorer.net工具中驗(yàn)證一下

image.png

image.png

控制臺打出customKeyCodeList,是一個Node數(shù)組


image.png

4.customKeyCodeList加上系統(tǒng)的keyCode聊训,構(gòu)造全量的keyCodeMap

// 全量的keyCode對照表,基于篇幅這里只列出3個
// https://developer.mozilla.org/zh-CN/docs/Web/API/KeyboardEvent/keyCode
let keyCodeMap = {46: 'delete',32: 'space',112: 'f1'}
//加上自定義keyCode構(gòu)造匯總所有的keyCodeMap,待會替換template內(nèi)容的時(shí)候需要使用
//結(jié)果:{46: 'delete',32: 'space',112: 'f1', customSpace: 'space', customDelete: 'delete'}
for(let i = 0;i< customKeyCodeList.length; i=i+2){
    Object.assign(keyCodeMap, {
        [customKeyCodeList[i].value] : keyCodeMap[customKeyCodeList[i+1].value]
    })
}

控制臺打出keyCodeMap構(gòu)造結(jié)果


image.png

5.Vue3要求: Vue.config.keyCodes不再支持,需要移除抱究。find到這個節(jié)點(diǎn),使用remove API移除

scriptAst.find(`Vue.config.keyCodes = $_$`).remove()

6.初始化template節(jié)點(diǎn)带斑,html模板需要帶{ parseOptions: { html: true } }參數(shù)

let templateAst = $(`<template>
 <div>
   <p>遷移:按鍵修飾符</p>
   <p>遷移策略:
         1.Vue3不再支持使用數(shù)字 (即鍵碼) 作為 v-on 修飾符 
         2.不再支持 config.keyCodes</p>
   <div class="mt20 text-left">
     <div>space:<input type="text" @keyup.space="keys('space')" /></div>
     <div>space:<input type="text" @keyup.32="keys('keycode 32 space')" /> </div>
     <div>space:<input type="text" @keyup.customSpace="keys('keycode 32 space')" /> </div>
   </div>
 </div>
</template>`, { parseOptions: { html: true } })

7.使用find鼓寺、each勋拟、attr API遍歷所有的標(biāo)簽以及它的屬性,使用keyCodeMap妈候,替換屬性名稱

//find+each遍歷所有的標(biāo)簽項(xiàng)
templateAst.find(['<$_$></$_$>', '<$_$ />']).each((node) => {
    //如果節(jié)點(diǎn)含有屬性,則遍歷它的屬性
    if (Array.isArray(node.attr('content.attributes'))) {
        node.attr('content.attributes').forEach((attr) => {
            //使用上文構(gòu)造出來的匯總keyCodeMap,替換匹配到的屬性名 如@keyup.32 -> @keyup.space
            for (let keyItem in keyCodeMap) {
                if (attr.key.content.endsWith(`.${keyItem}`)) {
                    attr.key.content = attr.key.content.replace(`.${keyItem}`,`.${keyCodeMap[keyItem]}`)
                }
            }
        })
    }
})

這里用到的node.attr('content.attributes')敢靡,就是剛才從astexplorer.net工具查到的

image.png

8.最后輸出,大功告成苦银,對比一下轉(zhuǎn)換的結(jié)果


image.png
image.png

4 總結(jié)

這段代碼里的AST相關(guān)操作只有10行左右啸胧,其余都是核心轉(zhuǎn)換邏輯。GoGoCode可以像使用Jquery操作DOM的一樣的體驗(yàn)來操作AST幔虏,入門簡單使用也方便

starter里還有批量處理文件的demo
https://github.com/thx/gogocode/tree/main/packages/gogocode-starter
Github上提issues也很快就有回應(yīng)纺念!
https://github.com/thx/gogocode/issues?q=is%3Aissue+is%3Aclosed

實(shí)在是代碼轉(zhuǎn)換利器

如果文中有任何問題,歡迎您的反饋所计。謝謝柠辞,祝你有美好的一天!

GoGoCode 相關(guān)鏈接

GoGoCode的Github倉庫(新項(xiàng)目求star _github.com/thx/gogocod…

GoGoCode的官網(wǎng) gogocode.io/

可以來 playground 快速體驗(yàn)一下 play.gogocode.io/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末主胧,一起剝皮案震驚了整個濱河市叭首,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌踪栋,老刑警劉巖焙格,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夷都,居然都是意外死亡眷唉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門囤官,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冬阳,“玉大人,你說我怎么就攤上這事党饮「闻悖” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵刑顺,是天一觀的道長氯窍。 經(jīng)常有香客問我,道長蹲堂,這世上最難降的妖魔是什么狼讨? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮柒竞,結(jié)果婚禮上政供,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好鲫骗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布犬耻。 她就那樣靜靜地躺著,像睡著了一般执泰。 火紅的嫁衣襯著肌膚如雪枕磁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天术吝,我揣著相機(jī)與錄音计济,去河邊找鬼。 笑死排苍,一個胖子當(dāng)著我的面吹牛沦寂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淘衙,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼传藏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了彤守?” 一聲冷哼從身側(cè)響起毯侦,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎具垫,沒想到半個月后侈离,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筝蚕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年卦碾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片起宽。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡洲胖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坯沪,到底是詐尸還是另有隱情宾濒,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布屏箍,位于F島的核電站,受9級特大地震影響橘忱,放射性物質(zhì)發(fā)生泄漏赴魁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一钝诚、第九天 我趴在偏房一處隱蔽的房頂上張望颖御。 院中可真熱鬧,春花似錦、人聲如沸潘拱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芦岂。三九已至瘪弓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間禽最,已是汗流浹背腺怯。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留川无,地道東北人呛占。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像懦趋,于是被迫代替她去往敵國和親晾虑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容