老舊項(xiàng)目前端代碼刪減 15%,我是如何做的

公司有一個(gè)數(shù)據(jù)BI平臺(tái)羡藐,它的起源是一個(gè)開源型的項(xiàng)目DataEase(一個(gè)開源數(shù)據(jù)可視化分析工具,幫助用戶通過拖拽交互做儀表搭建和視圖制作悯许、分享的低代碼平臺(tái)仆嗦。

關(guān)于DataEase:
官網(wǎng)地址:https://dataease.io/index.html
github代碼地址:https://github.com/dataease/dataease/

一、問題背景

在接手這個(gè)項(xiàng)目的時(shí)候先壕,它距離第一次代碼提交已經(jīng)有22個(gè)月瘩扼,代碼量共計(jì)約16w行代碼左右谆甜。而因?yàn)槭腔陂_源代碼庫加以修改的,很多文件的最近一次更新甚至還是在22個(gè)月前(也就是首次提交的時(shí)候)邢隧,很多代碼的存在可能隨著某些功能被放棄店印,也已經(jīng)不再被需要了,但是前面的維護(hù)同學(xué)也沒有勇于做必要的刪除倒慧。

對(duì)于我這個(gè)現(xiàn)任的代碼維護(hù)者,就經(jīng)常遇到看到某一個(gè)功能點(diǎn)包券,依據(jù)代碼debug后到某個(gè)組件上纫谅,再查看組件的調(diào)用時(shí)候有N個(gè)調(diào)用方。但是評(píng)估改動(dòng)的影響面和工作量后溅固,一個(gè)個(gè)找出來卻發(fā)現(xiàn)很多個(gè)調(diào)用方根本早就是被廢棄了付秕,屬于不該存在的調(diào)用方。多次這樣的情況發(fā)生之后侍郭,這就很困擾我的開發(fā)效率询吴。所以決心好好整治一下這些被廢棄的,不該存在的冗余代碼亮元。

二猛计、方案思考

想找出哪些組件(或者文件)是無用的,最先想到的肯定是構(gòu)建編譯時(shí)候爆捞,構(gòu)建工具可以基于ES module的靜態(tài)分析對(duì)冗余節(jié)點(diǎn)做Tree shaking的機(jī)制奉瘤。那么我們是不是可以從結(jié)果出發(fā)來倒推,把被Tree shaking掉的節(jié)點(diǎn)文件都找出來呢煮甥?

Tree shaking 是一個(gè)通常用于描述移除 JavaScript 上下文中的未引用代碼 (dead-code) 行為的術(shù)語盗温。

它依賴于 ES2015 中的 importexport 語句,用來檢測(cè)代碼模塊是否被導(dǎo)出成肘、導(dǎo)入卖局,且被 JavaScript 文件使用。

在現(xiàn)代 JavaScript 應(yīng)用程序中双霍,我們使用模塊打包 (如webpackRollup) 將多個(gè) JavaScript 文件打包為單個(gè)文件時(shí)自動(dòng)刪除未引用的代碼砚偶。這對(duì)于準(zhǔn)備預(yù)備發(fā)布代碼的工作非常重要,這樣可以使最終文件具有簡(jiǎn)潔的結(jié)構(gòu)和最小化大小店煞。

以webpack為例蟹演,能做編譯構(gòu)建后的資源分析的插件有webpack-bundle-analyzer , @statoscope/webpack-plugin等。

三顷蟀、實(shí)現(xiàn)方案

1酒请、拿到工程里所有待檢測(cè)的文件

我這里是直接通過shell腳本的方式得到src下所有的.js, .ts, .vue文件的文件名,然后輸出到output.txt文件鸣个。也有同學(xué)提到羞反,可以直接fast-glob這個(gè)包來做文件名收集布朦,當(dāng)然也是可以的。用你喜歡的就好昼窗。

# 進(jìn)入到src文件夾下
cd src

# 找到所有的.js, .ts, .vue文件的文件名是趴,輸出到src/output.txt文件
find . -type f ( -name "*.js" -o -name "*.ts" -o -name "*.vue" ) -exec echo {} ; > output.txt

下面這是得到的.js, .ts, .vue所有文件的文件路徑(示例):

App.vue
websocket/index.js
plugins/Blob.js
layout/index.vue
layout/mixin/ResizeHandler.js
layout/components/Sidebar/index.vue
…………
# 共計(jì)706個(gè)文件

修改一下上面的shell腳本,就可以獲取到所有的圖片文件(這里主要是:.png, .jpeg, .jpg, .svg文件)澄惊,腳本文件:

# 進(jìn)入到src文件夾下
cd src

# 找到所有的.js, .ts, .vue文件的文件名唆途,輸出到src/output.txt文件
find . -type f ( -name "*.png" -o -name "*.jpeg" -o -name "*.jpg" -o -name "*.svg" ) -exec echo {} ; > outputImage.txt

得到的圖片類文件的文件outputImage.txt:

components/canvas/assets/title.jpg
components/canvas/assets/bg-kj-1.jpg
components/canvas/assets/iconfont/iconfont.svg
icons/svg/task.svg
icons/svg/arrow-down.svg
icons/svg/system.svg
icons/svg/web-msg.svg
icons/svg/eye-open.svg
……
# 共計(jì)191個(gè)文件

二、選擇一個(gè)靜態(tài)資源編譯工具做Tree-shaking檢測(cè)

1掸驱、Webpack-bundle-analyzer

Webpack-bundle-analyzer的使用比較廣泛肛搬,github的star數(shù)也相當(dāng)多。我這里是基于Vue-cli v5的vue項(xiàng)目毕贼,本身是已經(jīng)集成了Webpack-bundle-analyzer插件温赔,只需要在構(gòu)建的時(shí)候在命令后加上--report就可以在構(gòu)建的時(shí)候同時(shí)產(chǎn)出report.html文件,打開后如下圖所示:

[圖片上傳失敗...(image-ebf446-1713856065422)]

這里可以看到構(gòu)建后的產(chǎn)出的靜態(tài)資源文件鬼癣,以及每個(gè)資源包的構(gòu)成分別是哪些依賴包或者業(yè)務(wù)文件陶贼。

React工程的話可以自行參考webpack官網(wǎng)來進(jìn)行配置:https://webpack.js.org/api/cli/#analyzing-bundle

2、 @statoscope/webpack-plugin

@statoscope/webpack-plugin的功能類似于webpack-bundle-analyzer待秃,雖然star數(shù)稍微低一點(diǎn)拜秧,但是功能也很強(qiáng)。配置用法可以自行參考其github地址:https://github.com/statoscope/statoscope/tree/master/packages/webpack-plugin

我這里的配置僅代表我本身锥余,畢竟我這只是個(gè)vue-cli項(xiàng)目的vue.config.js的配置:

if (process.env.VUE_APP_RUN_ENV !== 'development') {
  plugins = plugins.concat([
    new BundleStatsWebpackPlugin({
      json: false,
      html: true,
      outDir: './reports',
    }),
    new StatoscopeWebpackPlugin({
      saveReportTo: path.resolve(__dirname, 'dist/reports/statoscope-report.html'),
      saveStatsTo: path.resolve(__dirname, 'dist/reports/statoscope-report.json'),
      normalizeStats: false,
      saveOnlyStats: false,
      disableReportCompression: false,
      statsOptions: {},
      watchMode: false,
      name: 'some-name',
      open: false,
      compressor: 'gzip',
      reports: [],
      extensions: [],
    }),
  ])
}

來看一下編譯生產(chǎn)的report/statoscope-report.html文件:

[圖片上傳失敗...(image-bcc8d9-1713856065422)]

它有一個(gè)EntryPoints入口和Modules入口腹纳,前者是基本入口分析都引用了誰,后者是反向的根據(jù)模塊來分析它被誰調(diào)用了驱犹。

基于這些我就可以分析到底哪些文件是有出現(xiàn)在構(gòu)建的結(jié)果里的嘲恍。尤其是 @statoscope/webpack-plugin的構(gòu)建結(jié)果,可以看到除了report/statoscope-report.html雄驹,還生成了一個(gè)report/statoscope-report.json文件佃牛。這里正式描述依賴關(guān)系的文件,這個(gè)很重要医舆。是下面要用到的文件俘侠。

三、檢測(cè)未被引用的文件

下面就是利用這些文件路徑來檢測(cè)哪些是未被引用過的蔬将,附檢測(cè)的腳本代碼:

const fs = require('fs')
const readline = require('readline')

const filePath = './output.txt' // 替換為你的文本文件路徑

const readStream = fs.createReadStream(filePath)
const rl = readline.createInterface({
  input: readStream,
  crlfDelay: Infinity, // 處理Windows的換行符
})

const lines = []

rl.on('line', (line) => {
  // 每行的內(nèi)容將會(huì)觸發(fā)這個(gè)回調(diào)
  lines.push(line)
})

rl.on('close', () => {
  // 文件讀取完畢
  console.log('文件讀取完畢') // 輸出包含每行字符串的數(shù)組
})

const largeFilePath = '../dist/reports/statoscope-report.json' // 替換為你的大文件路徑
// const targetString = 'yourTargetString' // 替換為你要查找的字符串

const readStream2 = fs.createReadStream(largeFilePath)
const rl2 = readline.createInterface({
  input: readStream2,
  crlfDelay: Infinity, // 處理Windows的換行符
})

const foundStrings = new Set()

rl2.on('line', (line) => {
  // 在每一行中查找目標(biāo)字符串
  lines.forEach((targetString) => {
    if (!line.includes(targetString)) {
      foundStrings.add(targetString)
    }
  })
})

rl2.on('close', () => {
  // 文件讀取完畢爷速,輸出所有找到的字符串
  const resultArray = Array.from(foundStrings)
  console.log('check end')
  const resultPath = './NoReferenceResult.txt'
  // 將字符串寫入文件
  fs.writeFile(resultPath, resultArray.join('\n'), (err) => {
    if (err) {
      console.error('Error writing to file:', err)
    } else {
      console.log('File written successfully:', resultPath)
    }
  })
})

這里檢測(cè)結(jié)果的產(chǎn)物是一個(gè)NoReferenceResult.txt文件,這里直接貼一下結(jié)果:

components/TreeSelector/index.vue
components/SizeSelect/index.vue
components/LangSelect/index.vue
components/Notification/index.vue
components/GridButton/index.vue
components/business/complex-table/index.vue
……
# 共計(jì)135個(gè)文件

這里未被引用的文件合計(jì)有2w多行代碼霞怀,差不多占據(jù)了總代碼行數(shù)的14%左右的代碼量了惫东。

同樣的還有未被引用過的圖片:

components/canvas/assets/iconfont/iconfont.svg
icons/svg/table-pivot.png
assets/theme-dark.png
assets/theme-custom.png
assets/panel/show_all.png
assets/drag-indicator.png
assets/banner.png
assets/DataEase-black.png
assets/fill_radio.png
assets/deV.png
assets/theme-default.png
assets/DataEase-color.png
assets/blue_1.svg
assets/login-desc.png
assets/template.png
assets/avatar.jpeg
……
# 30多個(gè)未被引用過的圖片文件

四、后續(xù)

第一次檢測(cè)出這么多文件的時(shí)候,我是及其震驚的廉沮。竟然有這么多無用的代碼颓遏,2w多行啊V褪薄叁幢!當(dāng)時(shí)刪除的時(shí)候還是對(duì)著這些文件名一個(gè)個(gè)在代碼里做了搜索的,確實(shí)是一處引用都沒有坪稽,才敢放心刪除曼玩。刪除后又灰度了兩周才敢推全量上線的,但事實(shí)證明:屁事沒有啊窒百,干就完了兄弟們演训。

親身經(jīng)歷證明,刪代碼可比寫代碼解壓太多了哇~1戳!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拂募,一起剝皮案震驚了整個(gè)濱河市庭猩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌陈症,老刑警劉巖蔼水,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異录肯,居然都是意外死亡趴腋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門论咏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來优炬,“玉大人,你說我怎么就攤上這事厅贪〈阑ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵养涮,是天一觀的道長(zhǎng)葵硕。 經(jīng)常有香客問我,道長(zhǎng)贯吓,這世上最難降的妖魔是什么懈凹? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮悄谐,結(jié)果婚禮上介评,老公的妹妹穿的比我還像新娘。我一直安慰自己尊沸,他們只是感情好威沫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布贤惯。 她就那樣靜靜地躺著,像睡著了一般棒掠。 火紅的嫁衣襯著肌膚如雪孵构。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天烟很,我揣著相機(jī)與錄音颈墅,去河邊找鬼。 笑死雾袱,一個(gè)胖子當(dāng)著我的面吹牛恤筛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芹橡,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼林说,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼腿箩!你這毒婦竟也來了弓乙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤追逮,失蹤者是張志新(化名)和其女友劉穎钮孵,沒想到半個(gè)月后巴席,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荧库,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚪战,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡进副,死狀恐怖影斑,靈堂內(nèi)的尸體忽然破棺而出片迅,到底是詐尸還是另有隱情柑蛇,我是刑警寧澤空另,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布摄杂,位于F島的核電站坝咐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏析恢。R本人自食惡果不足惜墨坚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氮昧。 院中可真熱鬧框杜,春花似錦、人聲如沸袖肥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽椎组。三九已至油狂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寸癌,已是汗流浹背专筷。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蒸苇,地道東北人磷蛹。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像溪烤,于是被迫代替她去往敵國(guó)和親味咳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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