本文大綱介紹導(dǎo)語: 隨著業(yè)務(wù)的增長和開發(fā)團(tuán)隊(duì)的成員快速增加,其中很多新人來自于五湖四海各大門派,在編碼的風(fēng)格和習(xí)慣中也出現(xiàn)各異。 通常在相互 codereview 時(shí)發(fā)現(xiàn)很多代碼上的問題,久而久之代碼出現(xiàn)了代碼難以維護(hù)的問題,甚至還會(huì)出現(xiàn)低級錯(cuò)誤。 因此,我嘗試在前端代碼質(zhì)量的管控上做了些探索,也總結(jié)了一些經(jīng)驗(yàn)分享給大家。
作者:鄭振波
編碼規(guī)范
冗余文件與代碼
1. 編碼規(guī)范在一些老項(xiàng)目里我們常會(huì)遇到以下問題:
相信編碼規(guī)范對于大家來說不算是陌生,如果在 9102 年再次聊起這個(gè)話題,恐怕耳朵會(huì)起繭,但編碼規(guī)范從制定到落地是一個(gè)艱難的旅程,特別是對于不同成員的編碼習(xí)慣,還有棘手的祖?zhèn)鞔a。無論你是老司機(jī)還是新手不妨了解一下。
1.1 編碼規(guī)范的制定
如何制定編碼規(guī)范?這是一個(gè)永恒的話題,甚至出現(xiàn)過開發(fā)者按照自己的習(xí)慣和想法不停的去修改 eslint rules,沒錯(cuò),主觀性非常強(qiáng)的開發(fā)者就會(huì)這么干,最后發(fā)現(xiàn) eslint rules 成了一鍋粥。
兼顧習(xí)慣:盡可能兼顧團(tuán)隊(duì)各成員習(xí)慣,人是有個(gè)性的,要兼顧似乎不大可能。
規(guī)則從嚴(yán):規(guī)則越嚴(yán)格越好,也絕不讓他松散無約束。
投個(gè)票:投票似乎是最民主的決定,但往往最具爭議的 rules 會(huì)出現(xiàn)票數(shù)差異不大。
如果你能從以上三個(gè)方法中取得成果,那說明你是老板,這一切就會(huì)變得太簡單了。但無論如何,每一個(gè)被擴(kuò)展的?rule?都能找到具支持點(diǎn)和反駁點(diǎn),在制定規(guī)范時(shí)同學(xué)們通常往往會(huì)在幾個(gè)點(diǎn)去發(fā)表他的意見:
習(xí)慣:“我一直都這樣干,沒問題”
業(yè)界標(biāo)準(zhǔn):“你去看某某大公司的開源代碼吧”
必要性:“行尾不加分號(hào)我從沒見過跑不起來的JS”
耗時(shí):“按一次 tab 比按兩次 tab 省時(shí)省力;行尾加分號(hào)簡直浪費(fèi)生命”
1.2 在編碼質(zhì)量和編碼效率之間取得平衡有沒有辦法可以解決這些爭論?怎樣取得平衡?開源社區(qū)各團(tuán)隊(duì)開源出的 eslint rules 可以說是遍地開花,prettier,eslint-config-standard,airbnb 等等,在編碼規(guī)范選型時(shí)應(yīng)該考慮以下幾點(diǎn):
適合項(xiàng)目的技術(shù)選型:比如我們的團(tuán)隊(duì)技術(shù)棧使用了 React 、Node.js,ES6,那么就可以很清晰地知道怎么選擇方向了。
社區(qū)認(rèn)可度高:相信社區(qū)爭論程度不亞于團(tuán)隊(duì)成員,如果一個(gè)規(guī)范得到 stars 超過 1w,已經(jīng)是很了不起的事情了。
是否有插件支持:能夠支持 ESLint,JSCS 等。
基于以上標(biāo)準(zhǔn),我們選擇了超過 8w + 由 airbnb 前端團(tuán)隊(duì)維護(hù)的 eslint rules。 標(biāo)準(zhǔn)制定后, 如何讓團(tuán)隊(duì)成員快速適應(yīng)起來?
配置編輯器:如果使用 VSCode,可以配置 "eslint.autoFixOnSave": true,這樣保存代碼時(shí)會(huì)自動(dòng)根據(jù) eslint rules 去 fix 代碼,同學(xué)們就很舒服了。
編輯器插件:如果使用 VSCode 可以安裝 Eslint 插件,這樣可以實(shí)時(shí)提示不規(guī)范的代碼。
構(gòu)建時(shí)提示: 如果使用 webpack ,可以使用 eslint-loader,再配合 eslint-friendly-formatter 可以給到開發(fā)者很好的提示。可以參考該文章 webpack引入eslint詳解
這樣 eslint 規(guī)范就初步落地了。
1.3 整改祖?zhèn)鞔a定制好規(guī)范并落地后,如何對于祖?zhèn)鞔a怎么辦?于是我們又遇到不同的聲音:
這代碼不是我寫的:”誰寫誰來 fix 啊“
我不敢改: “改出問題要背鍋怎么說”
下次再改:“趕時(shí)間發(fā)布呢,要不就下次再改”
eslint-disable:“disable 大法好,沒有東西可以攔住我了”
以下是我們對祖?zhèn)鞔a的整改之路: 首先要看看問題有多嚴(yán)重:
npx eslint src
25W+ Eslint 報(bào)錯(cuò),這不知道要改到什么猴年馬月了。
但經(jīng)過排查發(fā)現(xiàn),這里面大部分報(bào)錯(cuò)是來自于第三方庫,但又不是 npm 包,這些文件往往是不能滿足當(dāng)前的編碼規(guī)范的,并且有部分是經(jīng)過代碼壓縮,更不應(yīng)該走 eslint 檢查。屏蔽掉第三方文件的檢測后,剩下的 eslint errors 還有 2w+,錯(cuò)誤歸類:
可以發(fā)現(xiàn)錯(cuò)誤類型最多的是換行符。
在文本處理中,各操作系統(tǒng)也是有自己的一套標(biāo)準(zhǔn):
Dos 和 windows 采用“回車+換行,CR/LF”表示下一行; UNIX/Linux 采用“換行符,LF”表示下一行; 蘋果機(jī)(MAC OS 系統(tǒng))則采用“回車符,CR”表示下一行。
所以,如果團(tuán)隊(duì)中還有 windows 玩家那么創(chuàng)建文件的換行符就是 CRLF,這也談不上是什么很大的缺點(diǎn),但在如果遇上了 Vim 或 Emacs 玩家打開文件就會(huì)看到這樣的情況:
每行后面會(huì)帶上個(gè) ^M。為了維護(hù)代碼世界的和平,通常需要統(tǒng)一轉(zhuǎn)換為 LF 換行符:
設(shè)置 IDE 換行符,如 VSCode:
VSCode 默認(rèn)配置:文件 - 首選項(xiàng) - 設(shè)置 -搜索:默認(rèn)行尾字符。修改為
EditorConfig: 如果你的項(xiàng)目中有 EditorConfig 那就更好了:
#Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true
配置 git config:可以在 git commit 時(shí)把代碼統(tǒng)一轉(zhuǎn)為 LF,那么可以了解一下 git config core.autocrlf ,也許你會(huì)見過這個(gè)配置,但不一定正確使用,其實(shí)他有3個(gè)值可配置:
ture: git pull 時(shí)會(huì)把 LF 結(jié)尾轉(zhuǎn)為 CRLF false: git pull 時(shí)不做任何轉(zhuǎn)換 input: git pull 時(shí)會(huì)把 CRLF 轉(zhuǎn)換為 LF
那么這里應(yīng)該使用的是 git conifg core.autocrlf input 以上任何一條都可以解決你的換行符問題。
解決好這一切之后,可以嘗試讓 ESLint 自動(dòng)修復(fù)一波了: npx eslint src --fix
自動(dòng)修復(fù)后還有 800+ ESLint 報(bào)錯(cuò),于是打開這些代碼 review 后,發(fā)現(xiàn)有很多問題,以為規(guī)范人人都懂,正如那句電影臺(tái)詞**“聽過很多道理,卻依然過不好這一生”**。 這些都是很低級的錯(cuò)誤,如果你還沒有使用上 ESLint 那最好別太相信自己的代碼。
800+ 的錯(cuò)誤分布在各個(gè)頁面,可以給團(tuán)隊(duì)成員每人分配幾個(gè)頁面修復(fù)并分批上線,這樣大規(guī)模的修復(fù)最重要的是發(fā)布后的監(jiān)控:
1.4 曾經(jīng)以為 ESLint 是萬能的
也許你會(huì)認(rèn)為 ESLint 沒有報(bào)錯(cuò)那就 O**K了,其實(shí)坑往往沒那么容易被發(fā)現(xiàn),就像下面這個(gè)例子:
這里提示絕對路徑的引入應(yīng)寫在相對路徑引入的前面,于是快速改他一波: 這里就有問題了,你看出來了嗎?應(yīng)該怎么改?1.5 守住規(guī)則
我們經(jīng)過制定規(guī)范,代碼整改,接下來需要守住規(guī)則,否則一切徒勞
git hook:可以使用 pre-commit,husky 等工具來配置 git 鉤子,配合上 npm script 可以做到在提交代碼前執(zhí)行 eslint 命令來檢測變更文件是否符合規(guī)范,否則 exit 非零值來終止 git commit。但在前端使用 git hook 缺點(diǎn)也是有的,比如每次提交代碼都要等待 eslint 一遍,導(dǎo)致開發(fā)體驗(yàn)大大下降;也會(huì)出現(xiàn)有同學(xué)自行刪除 pre-commit hook 文件來繞過檢測的情況;也可以通過添加 --no-verify 來關(guān)閉檢測。
web hook:好處是使用服務(wù)端來做校驗(yàn),無法在前端繞過,缺點(diǎn)是需要使用服務(wù)器資源。關(guān)于如何搭建 web hook,可以參考這篇文章
1.6 關(guān)于前端代碼規(guī)范的其他思考以上提到的是關(guān)于 JS 代碼規(guī)范的內(nèi)容,對于 CSS 也可以使用 stylelint 來做規(guī)范檢測,但這些更多的是對代碼的格式做規(guī)范,如果想把代碼寫好 ESLint 之類的并不是全能的,比如代碼的整潔之道,這里列舉了不少可以參考的范式,恰又是 ESLint 無法幫你 hold 住的點(diǎn),所以 ESLint 并不是萬能的。
2.冗余文件與代碼 2.1 關(guān)于冗余文件也許你會(huì)認(rèn)為冗余文件是一個(gè)問題,但他不是一個(gè)很關(guān)鍵的痛點(diǎn),如果你的團(tuán)隊(duì)追求極致,有非常的代碼潔癖,那么冗余文件也應(yīng)該重視起來。即使你是一名老鳥,也有可能產(chǎn)生冗余文件。
2.2 為什么會(huì)產(chǎn)生冗余文件在代碼的迭代過程中,往往容易忽略刪除相應(yīng)的文件,大概有兩種場景: 1、刪除 JS 代碼中的 require,卻忘記刪除相應(yīng)的文件(img/css/js/etc.)。 2、刪除 CSS 中的 background ,忘記刪除相應(yīng)的圖片文件。 刪除代碼很痛快,只要頁面刷新一波沒有報(bào)錯(cuò)就覺得 o**k 了,日積月累的冗余文件慢慢讓整個(gè)倉庫越來越大。
2.3 清理冗余文件如果使用 webpack 構(gòu)建,那就可以很方便地分析出整個(gè)項(xiàng)目的依賴關(guān)系。 第一步:在根目錄跑命令,把文件的依賴關(guān)系導(dǎo)到 stats.json 中,這個(gè)步驟耗時(shí)略長,我在項(xiàng)目中跑了一次,1420 個(gè)文件耗時(shí) 35s。
webpack --json > ./stats.json
第二步:使用 glob 獲取目錄下的所有文件路徑:
glob("!(node_modules)/**/*.*")
結(jié)合第一步生成的 stats.json 可以過濾出未被引用的文件。
2.4 冗余代碼要分析項(xiàng)目中冗余的CSS,其實(shí)是比較困難的,主要原因有 3 個(gè)方面: 1、頁面的元素或組件的嵌套:導(dǎo)致無法只從靜態(tài)分析的層面上判斷樣式是否有作用于對應(yīng)的元素上。 2、樣式的全局作域:a.css 中聲明一個(gè)樣式,他可以作用于頁面上的任何一個(gè) dom,這樣分析起來要遍歷項(xiàng)目中所有的 dom 和 css,一個(gè)樣式的聲明需要檢查所有的 dom,如果有N個(gè)樣式聲明那將會(huì)有非常大的計(jì)算量。 3、css 沒有約束: 多個(gè) css 文件的樣式也可以作用于一個(gè) dom 元素上,因?yàn)橥鶗?huì)用到開源的 ui 庫,會(huì)根據(jù)設(shè)計(jì)的要求對相應(yīng)的 dom 元素做樣式覆蓋,所以這種過于靈活的特性帶來的不可控造成難以管理。
CSS Modules 可以把 css 作用域收斂,可以顯式聲明哪個(gè) class 樣式作用于 dom 上,可以保證某個(gè)組件的樣式不會(huì)影響到其他組件:
樣式與 dom 形成了強(qiáng)依賴關(guān)系,這樣就可以便于做靜態(tài)分析,可以借助 eslint-plugin-css-modules: 如果 scss 里面存在未使用到的 className,會(huì)得到提示: 如果在代碼中使用了未定義的 className,也會(huì)有提示:
在代碼迭代中,很有可能刪除掉一些方法的使用,那么會(huì)在 Class 留下一些多余的方法,這些也是難以通過 eslint 來檢測到的,因?yàn)闆]辦法判斷這些方法在實(shí)例化后,是否會(huì)在某個(gè)時(shí)刻被使用到。如果要找出這些冗余的方法,也需要從整個(gè)項(xiàng)目開始分析所有 JS 的依賴關(guān)系,那么計(jì)算量就會(huì)非常大,并且很耗時(shí)。
目前沒有什么好的辦法來解決這個(gè)問題,或許可以通過兩種方式來分析出來: 1、命名約定: 比如以下劃線開頭的方法是私有方法,那么就可以只針對本文件所有的私有方法是否被使用來做分析了。 2、注釋標(biāo)記:如果不喜歡下劃線的方式,那么也可以考慮添加注釋來標(biāo)記。
1、刪除代碼要留心 2、分析冗余 3、合理運(yùn)用工具 4、發(fā)布后監(jiān)控
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/7309.html
摘要:前言月份開始出沒社區(qū),現(xiàn)在差不多月了,按照工作的說法,就是差不多過了三個(gè)月的試用期,準(zhǔn)備轉(zhuǎn)正了一般來說,差不多到了轉(zhuǎn)正的時(shí)候,會(huì)進(jìn)行總結(jié)或者分享會(huì)議那么今天我就把看過的一些學(xué)習(xí)資源主要是博客,博文推薦分享給大家。 1.前言 6月份開始出沒社區(qū),現(xiàn)在差不多9月了,按照工作的說法,就是差不多過了三個(gè)月的試用期,準(zhǔn)備轉(zhuǎn)正了!一般來說,差不多到了轉(zhuǎn)正的時(shí)候,會(huì)進(jìn)行總結(jié)或者分享會(huì)議!那么今天我就...
摘要:前言前端模塊化,主要是解決兩個(gè)問題命名空間沖突,文件依賴管理。目前解決的方法是模塊化命名空間各個(gè)模塊的命名空間獨(dú)立。模塊化構(gòu)建工具,等是用來組織前端模塊的構(gòu)建工具加載器。 前言 前端模塊化,主要是解決兩個(gè)問題——命名空間沖突,文件依賴管理。 坑___命名空間沖突 我自己測試好的代碼和大家合并后怎么起沖突了? 頁面腳本的變量或函數(shù)覆蓋了公有腳本的。 坑___文件依賴管理 明明項(xiàng)目需...
摘要:前端項(xiàng)目如何管理前端項(xiàng)目的管理分為兩個(gè)維度項(xiàng)目內(nèi)的管理與多項(xiàng)目之間的管理。具體可以參考項(xiàng)目如何進(jìn)行多人協(xié)作開發(fā)。組件項(xiàng)目更不用說了,值得提一下的是組件項(xiàng)目的版本號(hào)應(yīng)當(dāng)符合語義化版本規(guī)范。 前端項(xiàng)目如何管理 前端項(xiàng)目的管理分為兩個(gè)維度:項(xiàng)目內(nèi)的管理與多項(xiàng)目之間的管理。 1. 項(xiàng)目內(nèi)的管理 在一個(gè)項(xiàng)目內(nèi),當(dāng)有多個(gè)開發(fā)者一起協(xié)作開發(fā)時(shí),或者功能越來越多、項(xiàng)目越來越龐大時(shí),保證項(xiàng)目井然有序的進(jìn)...
摘要:而測試驅(qū)動(dòng)開發(fā)技術(shù)并不只是單純的測試工作。需求向來就是軟件開發(fā)過程中感覺最不好明確描述易變的東西。這里說的需求不只是指用戶的需求,還包括對代碼 可能很多人和我一樣, 首次聽到前端架構(gòu)這個(gè)詞, 第一反應(yīng)是: 前端還有架構(gòu)這一說呢? 在后端開發(fā)領(lǐng)域, 系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵, 因此架構(gòu)師備受重視, 早在開發(fā)工作啟動(dòng)之前, 他們就被邀請加入到項(xiàng)目中, 而且他們會(huì)跟客戶討論即將建成的平臺(tái)的...
摘要:而測試驅(qū)動(dòng)開發(fā)技術(shù)并不只是單純的測試工作。需求向來就是軟件開發(fā)過程中感覺最不好明確描述易變的東西。這里說的需求不只是指用戶的需求,還包括對代碼 可能很多人和我一樣, 首次聽到前端架構(gòu)這個(gè)詞, 第一反應(yīng)是: 前端還有架構(gòu)這一說呢? 在后端開發(fā)領(lǐng)域, 系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵, 因此架構(gòu)師備受重視, 早在開發(fā)工作啟動(dòng)之前, 他們就被邀請加入到項(xiàng)目中, 而且他們會(huì)跟客戶討論即將建成的平臺(tái)的...
閱讀 2310·2021-10-11 10:59
閱讀 2601·2021-10-11 10:58
閱讀 3303·2021-09-08 09:35
閱讀 3782·2021-09-02 15:21
閱讀 1454·2019-08-30 15:53
閱讀 2608·2019-08-29 14:16
閱讀 2067·2019-08-26 14:00
閱讀 2942·2019-08-26 13:52