阿里媽媽出的新工具,給批量修改項(xiàng)目代碼減輕了痛苦

作為一個(gè)程序員,當(dāng)然總是期望自己的代碼能「一次編寫,四處運(yùn)行」,但真實(shí)經(jīng)驗(yàn)往往是「一處修改,百處填坑」,依賴落后了好幾個(gè)版本了想要升級(jí)、老代碼已經(jīng)看著很不爽了打算重構(gòu),都需要下堅(jiān)決的決心,畢竟哪里漏掉了或者改錯(cuò)了都可能釀成大禍,我們一般都怎么搞呢?

放棄不搞

頓時(shí)就減輕了痛苦有木有…但如果你堅(jiān)持要搞,請(qǐng)往下看!

土辦法的真香和局限

對(duì)于一些簡(jiǎn)單的需求,比如最近在掘金上看到了一個(gè)例子,去掉項(xiàng)目中?console.log(xxx)?代碼,我相信大家平時(shí)遇到這種需求第一個(gè)想法都是直接選擇編輯器批量文本替換成空字符串:

利用正則表達(dá)式,我們還是可以搞定很多需求的,但這樣真的能包含所有情況么?有的同事是真的喜歡回車。

console.log('aaa')復(fù)制代碼

這種情況下,如果面對(duì)更復(fù)雜的需求或者嚴(yán)謹(jǐn)?shù)膱?chǎng)景,要么我們編寫更復(fù)雜的正則表達(dá)式,要么我們就不得不去硬肝 AST 操作了。

AST有點(diǎn)復(fù)雜

上網(wǎng)搜索了一下,還真找到了利用 jscodeshift 操作 AST 去掉 console.log 的示例:

exportdefault(fileInfo, api) => {constj = api.jscodeshift;constroot = j(fileInfo.source)constcallExpressions = root.find(j.CallExpression, {callee: {type:'MemberExpression',object: {type:'Identifier',name:'console'},? ? ? },? ? }? );? callExpressions.remove();returnroot.toSource();};復(fù)制代碼

這需要大家對(duì) AST 結(jié)構(gòu)比較熟悉,在編寫的時(shí)候需要對(duì)著解析好的節(jié)點(diǎn)結(jié)構(gòu)才能緩緩寫出,過一段時(shí)間再一看,也不會(huì)比彎彎繞繞的正則更好理解——大家平時(shí)太少接觸 AST 了。

試著結(jié)合一下

有一次正當(dāng)我為一個(gè)項(xiàng)目 API 大重構(gòu)發(fā)愁,準(zhǔn)備人肉爆肝的時(shí)候,我旁邊的小姐姐實(shí)在看不下去了——她的項(xiàng)目比我更早地做了重構(gòu),人家不僅沒爆肝,還順手做了個(gè)工具?GoGoCode,這個(gè)工具借鑒了 jQuery 的兩大思想:

選擇器鏈?zhǔn)秸{(diào)用

用這工具去掉?console.log(xxx)?,其實(shí)就是一句話的事:

const$ =require('gogocode')/** 刻意凌亂的代碼 **/constinput =`

? ? console

.log(`a, b,c`);

`// 關(guān)鍵代碼constoutput = $(input).replace('console.log()','').generate()console.log(output)復(fù)制代碼

它的創(chuàng)新之處就在于,把你輸入的?console.log()?解析成一段 AST 節(jié)點(diǎn)去源代碼里做節(jié)點(diǎn)樹的匹配,這樣自然就沒有代碼格式的問題了。你輸入的代碼就相當(dāng)于 jQuery 里面的選擇器,只不過這一次選擇的是代碼節(jié)點(diǎn)。

更多例子

清理?console.log?這個(gè)操作還是太簡(jiǎn)單了,我再舉一個(gè)栗子!

我們經(jīng)常使用這樣的枚舉列表:

constlist = [? {text:"A策略",value:1,tips:"Atip",? },? {text:"B策略",value:2,tips:"Btip",? },? {text:"C策略",value:3,tips:"Ctip",? },];復(fù)制代碼

突然有一天,為了統(tǒng)一代碼里的各種枚舉,我們需要把 text 屬性更名為 name,把 value 屬性更名為 id,這個(gè)用正則很難精確匹配容易誤傷,操作AST樹還有些麻煩,用?GoGoCode?只需要這么替換一下就行了:

const$ =require('gogocode')constinput =`

const list = [

? {

? ? text: "A策略",

? ? value: 1,

? ? tips: "Atip",

? },

? {

? ? text: "B策略",

? ? value: 2,

? ? tips: "Btip",

? },

? {

? ? text: "C策略",

? ? value: 3,

? ? tips: "Ctip",

? },

];

// ts的類型標(biāo)記,這種正則替換會(huì)被錯(cuò)誤替換的,在 gogocode 里就不會(huì)

const text: string = ''

// 這一段因?yàn)闆]有 value 就不會(huì)被選擇器匹配到,也不會(huì)被錯(cuò)誤替換

const cfg = {

? text: ''

}

`constoutput = $(input2).replace('{ text: $_$1, value: $_$2, $$$ }','{ name: $_$1, id: $_$2, $$$ }').generate();復(fù)制代碼

其中?$_$1?和?$_$2?相當(dāng)于正則中的通配符,但是在這里只會(huì)匹配代碼里有效的 AST 節(jié)點(diǎn),$$$?則可以匹配剩下的節(jié)點(diǎn),有點(diǎn)像 es6 里的?...?,這段代碼匹配出了?text?和?value?這對(duì)應(yīng)的值填給了?name?和?id,剩下的原封不動(dòng)放回去。

而下半部分我刻意加了一些「干擾代碼」,以往我通過字符串替換?text:為?name:的土辦法遇到這樣的就會(huì)誤傷了,但?GoGoCode?不會(huì)。

再看前一段社區(qū)里的一個(gè)例子

正巧,前一段我在掘金看到了文章?像玩 jQuery 一樣玩 AST,里面介紹了一個(gè)用 jscodeshift 進(jìn)行 React jsx 代碼轉(zhuǎn)換的例子:

打算對(duì)這樣一份代碼做修改:

從 @alifd/next 導(dǎo)入改成 antd

轉(zhuǎn)譯前 改成 轉(zhuǎn)譯后

Button 中 type 參數(shù)轉(zhuǎn)換:normal -> default,medium -> middle

Button 中有 text 參數(shù)的改成 type="link"

Button 中warning 參數(shù)的改成 danger

import*asReactfrom'react';importstylesfrom'./index.module.scss';import{ Button }from"@alifd/next";constBtn =() =>{return(

轉(zhuǎn)譯前

NormalPrirmarySecondaryNormalPrimarySecondaryNormal
);};exportdefaultBtn;復(fù)制代碼

大概是這樣:

need-to-insert-img

這種需求其實(shí)挺常見的,原文提供了一個(gè)?基于 jscodeshift 的實(shí)現(xiàn),深入到了 AST 進(jìn)行操作,但如果用?GoGoCode?就會(huì)直觀很多:

// 省略依賴和 inputconstoutput = $(input)? .replace(`import { $$$ } from "@alifd/next"`,`import { $$$ } from "antd"`)? .replace(`<h2>轉(zhuǎn)譯前</h2>`,`<h2>轉(zhuǎn)譯后</h2>`)? .replace(`<Button type="normal" $$$></Button>`,`<Button type="default" $$$></Button>`)? .replace(`<Button size="medium" $$$></Button>`,`<Button size="middle" $$$></Button>`)? .replace(`<Button text $$$></Button>`,`<Button type="link" $$$></Button>`)? .replace(`<Button warning $$$></Button>`,`<Button danger $$$></Button>`)? .generate();復(fù)制代碼

相信你不要講解也能知道這段代碼是要做什么了~

開源了,希望能得到大家的反饋

我覺得這個(gè)項(xiàng)目挺有趣的,可以說是專門給代碼做了一個(gè) replace 程序,小姐姐說我看到得太淺顯,其實(shí)這個(gè)項(xiàng)目不僅僅是 replace 這一招,這個(gè)項(xiàng)目支撐了我們幾個(gè)幾萬行前端工程的架構(gòu)升級(jí)計(jì)劃,就算需求更復(fù)雜也是有辦法搞定的,大家可以關(guān)注我們的賬號(hào)或?qū)?,后面作者?huì)發(fā)表更專業(yè)全面的介紹文章。

小姐姐是我們阿里媽媽 MUX 團(tuán)隊(duì)的葉兮,我們團(tuán)隊(duì)以前有過?iconfont、Rap、MockJS?這樣受到社區(qū)歡迎的項(xiàng)目,這一次我們把?GoGoCode?也開源到 Github:github.com/thx/gogocod…,希望能對(duì)同樣有大量代碼修改需求的朋友有所幫助。

我們很希望了解到大家會(huì)經(jīng)常遇到怎樣的轉(zhuǎn)換難題,如果你用現(xiàn)在?GoGoCode?不方便解決或者出了錯(cuò),希望你能提給我們(issue:https://github.com/thx/gogocode?QQ群:735216094)。

最后:新項(xiàng)目求 star 支持!

Github:https://github.com/thx/gogocode

官網(wǎng):gogocode.io

作者:阿里媽媽前端快爆

鏈接:https://juejin.cn/post/6938601548192677918

來源:掘金

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容