1 為什么要遷移 Vue3.x
說點(diǎn)什么呢俺陋?
總之豁延。。腊状。 這不是我的錯诱咏!
首先先要寫個案例,找到一個可執(zhí)行方案缴挖。
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ù)雜砌梆。
調(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í)在是勸退案例甘有。
正在我為這個項(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崆铡怪得!
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)
這里要做的有三件事:
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
- 初始化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)證一下
控制臺打出customKeyCodeList,是一個Node數(shù)組
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é)果
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工具查到的
8.最后輸出,大功告成苦银,對比一下轉(zhuǎn)換的結(jié)果
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/