<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          我是如何帶領(lǐng)團(tuán)隊(duì)從零到一建立前端規(guī)范的?

          共 11258字,需瀏覽 23分鐘

           ·

          2022-04-24 01:39

          關(guān)于本文

          作者:不要禿頭啊

          來自:https://juejin.cn/post/7085257325165936648

          前言

          不以規(guī)矩,不能成方圓。

          本人有幸經(jīng)歷了團(tuán)隊(duì)從缺乏標(biāo)準(zhǔn)到逐漸規(guī)范的一個(gè)過程,在此當(dāng)做記錄供大家參考。

          本文從為什么需要規(guī)范以及建立規(guī)范的重要性出發(fā),逐步引申出如何去建立適合自己團(tuán)隊(duì)的規(guī)范,詳細(xì)討論了前端具體涉及到的規(guī)范都有哪些,部分小節(jié)有具體的配置步驟和操作鏈接。

          文中涉及到的所有配置均放在github上的 Demo[1] 中,覺得不錯(cuò)的點(diǎn)個(gè)贊 ??????。

          下面我們開始吧??。

          為什么需要規(guī)范

          規(guī)范能給我們帶來什么好處,如果沒有規(guī)范會(huì)造成什么后果?這里主要拿代碼規(guī)范來說。

          統(tǒng)一代碼規(guī)范的好處:

          1. 提高代碼整體的可讀性、可維護(hù)性、可復(fù)用性、可移植性和可靠性,這會(huì)從根本上降低開發(fā)成本,也是最重要的一點(diǎn)。
          2. 保證代碼的一致性:軟件系統(tǒng)中最重要的因素之一就是編碼的一致性。如果編碼風(fēng)格一致,也更加易于維護(hù),因?yàn)閳F(tuán)隊(duì)內(nèi)任何人都可以快速理解并修改。
          3. 提升團(tuán)隊(duì)整體效率:開發(fā)人員通常需要花費(fèi)大量的時(shí)間來解決代碼質(zhì)量問題,如果都按照規(guī)范編寫,也有助于團(tuán)隊(duì)盡早發(fā)現(xiàn)問題,甚至完全預(yù)防問題,這將提高整個(gè)交付過程的效率。
          4. 減少code review期間一系列的爭(zhēng)議,因?yàn)槿狈?biāo)準(zhǔn),在爭(zhēng)議過程中雙方很難妥協(xié)(沒少因?yàn)檫@事爭(zhēng)論過??)。

          若不統(tǒng)一代碼規(guī)范,可能會(huì)造成的后果:

          1. 由于缺乏規(guī)范,導(dǎo)致代碼風(fēng)格不一,增加團(tuán)隊(duì)成員間的心理負(fù)擔(dān),極端情況下,某段代碼只有某個(gè)人能修改(俗稱屎山??)。
          2. 團(tuán)隊(duì)間協(xié)作更加困難:因?yàn)殚_發(fā)人員得適應(yīng)不同的風(fēng)格,會(huì)導(dǎo)致效率低下(閱讀代碼是我們花費(fèi)時(shí)間最多的地方)。
          3. 在code review期間可能經(jīng)常為類似的事情做過多的討論。
          4. 影響團(tuán)隊(duì)的生產(chǎn)力和質(zhì)量,嚴(yán)重的甚至?xí)绊憟F(tuán)隊(duì)和諧。

          為什么依然有很多團(tuán)隊(duì)缺乏規(guī)范

          在這件事上,很難達(dá)成一致是我認(rèn)為最重要的原因。并且,僅僅只是擁有規(guī)范也是不夠的:

          • 當(dāng)開發(fā)人員被要求在短時(shí)間內(nèi)完成任務(wù)時(shí),通常會(huì)回避質(zhì)量標(biāo)準(zhǔn)。
          • 團(tuán)隊(duì)中總是有一些有個(gè)性的人不會(huì)為了團(tuán)隊(duì)去改變自己的習(xí)慣。
          • 有些人在會(huì)議上就約定達(dá)成了一致,在會(huì)下依舊我行我素。
          • ...

          如何保持規(guī)范

          我曾想通過會(huì)議討論的方式來制定規(guī)范,但效果卻差強(qiáng)人意。將失敗的原因總結(jié)為大致幾點(diǎn):

          1. 在會(huì)議中,思維很容易發(fā)散,經(jīng)常出現(xiàn)的情況是討論了很多,卻很難有實(shí)際性的成效,在開發(fā)中依然有不少人選擇無視規(guī)則。
          2. 正式的會(huì)議往往很難組織,大家很難一起有空閑的時(shí)間來討論,一次/兩周 都很困難。
          3. 會(huì)議中對(duì)實(shí)際案例分析,提出若干點(diǎn)優(yōu)化建議后,沒有對(duì)問題的優(yōu)先級(jí)和側(cè)重點(diǎn)進(jìn)行劃分,導(dǎo)致實(shí)際效果并不好。
          4. 還有一點(diǎn)也是我自己的原因,組織會(huì)議的能力有待提升...??

          經(jīng)歷了上述的挫敗之后,經(jīng)過反復(fù)復(fù)盤總結(jié),決定換一種方式來執(zhí)行:

          1. 對(duì)規(guī)范問題進(jìn)行歸納分析并通過文檔記錄(wiki等),尋找業(yè)內(nèi)最佳解決方案,在團(tuán)隊(duì)內(nèi)進(jìn)行統(tǒng)一。
          2. 采用小步快跑的方式,有問題就解決問題,按照優(yōu)先級(jí)和重要性進(jìn)行排序劃分,依次將問題納入迭代,每個(gè)迭代重點(diǎn)解決其中幾個(gè)即好。
          3. 本迭代的規(guī)范問題絕不留到下個(gè)迭代,防止堆積(當(dāng)然,有時(shí)候還是得向項(xiàng)目經(jīng)理妥協(xié)?????)。
          4. 在code review過程中嚴(yán)格把關(guān),拒絕睜一只眼??閉一只眼??。
          5. 當(dāng)團(tuán)隊(duì)成員對(duì)具體某個(gè)規(guī)范有爭(zhēng)議時(shí),及時(shí)討論并定出結(jié)論。
          6. 沒有規(guī)則只是為了規(guī)則,制定規(guī)范的目的并不是一定要按照某某標(biāo)準(zhǔn)來執(zhí)行,更多的是團(tuán)隊(duì)成員達(dá)成一致即可。
          7. 鼓勵(lì)大家大膽的質(zhì)疑規(guī)則,若不能提高代碼的可讀性,可維護(hù)性,可復(fù)用性,可移植性和可靠性的規(guī)則都應(yīng)該被受到質(zhì)疑。
          8. 以身作則,船頭的方向不能偏航。

          經(jīng)過兩個(gè)月的迭代后,發(fā)現(xiàn)效果出奇的好??,大家的規(guī)范意識(shí)普遍增強(qiáng),當(dāng)遇到規(guī)范問題時(shí)也不再畏畏縮縮,而是大膽的拋出在群里討論。

          開發(fā)者需要建立和遵守的規(guī)范

          大致可以劃分成這幾個(gè)方向:

          • 開發(fā)流程規(guī)范
          • 代碼規(guī)范
          • git commit規(guī)范
          • 項(xiàng)目文件結(jié)構(gòu)規(guī)范
          • UI設(shè)計(jì)規(guī)范

          1. 開發(fā)流程規(guī)范

          這里可能有小伙伴有疑問了,開發(fā)流程規(guī)范不是項(xiàng)目經(jīng)理定的嗎???,跟我有什么關(guān)系?

          這里想告訴大家的是,開發(fā)流程在一定程度上應(yīng)該是由我們自己來掌控。不管是傳統(tǒng)開發(fā)的模式還是敏捷開發(fā)的模式,對(duì)于開發(fā)者來說核心依舊是高質(zhì)高效的完成用戶提出的需求。

          筆者曾見過不少開發(fā)者在拿到產(chǎn)品經(jīng)理的需求后就開始急匆匆的寫代碼,以此來體現(xiàn)他們的高效,但往往卻因?yàn)樾枨罄斫獠坏轿缓颓捌诖a欠缺設(shè)計(jì)導(dǎo)致bug率高和返工。

          如何找到適合自己的開發(fā)流程是需要依靠經(jīng)驗(yàn)來支撐的,需要反復(fù)總結(jié)和思考,最終達(dá)到高質(zhì)高效完成的目的。

          說一說筆者自己比較喜歡的開發(fā)流程:

          image.png

          在接收到需求后應(yīng)第一時(shí)間去了解這個(gè)需求的背景是什么?這么做到底有沒有解決用戶的痛點(diǎn)?或者說用戶更深層次的需求是什么?如果團(tuán)隊(duì)的產(chǎn)品經(jīng)理經(jīng)驗(yàn)不豐富,往往可以在這個(gè)階段砍掉很多不合理的需求(這一點(diǎn)真的很重要)

          對(duì)于復(fù)雜大功能往往還需要進(jìn)行技術(shù)方案調(diào)研技術(shù)方案設(shè)計(jì),并輸出詳細(xì)的設(shè)計(jì)文檔。涉及到細(xì)節(jié)上,則需要將數(shù)據(jù)流走向、組件設(shè)計(jì)等通過腦圖的形式呈現(xiàn)出來。

          2. 代碼規(guī)范之格式化規(guī)范

          由于每個(gè)開發(fā)者的IDE不同,即使IDE相同也會(huì)因?yàn)槊總€(gè)人的配置不一樣導(dǎo)致格式化的結(jié)果不一樣。如何確保團(tuán)隊(duì)內(nèi)開發(fā)人員采用統(tǒng)一的格式化配置呢?

          這里給推薦大家使用 prettier[2],它內(nèi)置了一套格式化的規(guī)則,具體配置:

          1). 安裝依賴:

          npm?install?--save-dev?--save-exact?prettier?
          //?or
          yarn?add?--dev?--exact?prettier
          復(fù)制代碼

          2). 創(chuàng)建一個(gè)空配置文件,讓編輯器和其他工具知道你正在使用 Prettier:

          echo?{}>?.prettierrc.json
          復(fù)制代碼

          3). 創(chuàng)建一個(gè).prettierignore[3]文件,讓 Prettier CLI 和編輯器知道哪些文件不能格式化,example:

          #?Ignore?artifacts:
          dist
          build
          coverage
          復(fù)制代碼

          4). 配置編輯器(VScode為例)

          IDE中安裝 Prettier-Code Formater[4] 插件:

          image.png

          找到IDE中設(shè)置模塊,搜索 format On Save,勾上這個(gè)就可以了。

          image.png

          現(xiàn)在當(dāng)我們 Ctrl + S 保存代碼時(shí),插件就會(huì)幫助我們自動(dòng)格式化了。

          這里有小伙伴要問了,要是有人將沒有格式化的代碼提交上去怎么辦?

          這時(shí)候就需要在 git commit 的階段自動(dòng)將提交的代碼進(jìn)行格式化,這里我們借助工具 husky[5],它主要可以幫助我們?cè)?git 階段檢查提交消息、運(yùn)行測(cè)試、檢查代碼等。沒接觸過的小伙伴可以去官網(wǎng)[6]了解一下,配置如下:

          • 安裝 husky[7]lint-staged[8]
          npm?install?--save-dev?husky?lint-staged
          npx?husky?install
          npm?set-script?prepare?"husky?install"
          npx?husky?add?.husky/pre-commit?"npx?lint-staged"
          //?or
          yarn?add?--dev?husky?lint-staged
          npx?husky?install
          npm?set-script?prepare?"husky?install"
          npx?husky?add?.husky/pre-commit?"npx?lint-staged"
          復(fù)制代碼
          • 然后將以下內(nèi)容添加到package.json中:
          {
          ??"lint-staged":?{
          ????"**/*":?"prettier?--write?--ignore-unknown"
          ??}
          }
          復(fù)制代碼

          這段配置的意思是:當(dāng)執(zhí)行 git commit 階段前,先執(zhí)行lint-staged,lint-staged中的內(nèi)容就是對(duì)暫存區(qū)的文件執(zhí)行格式化的命令。

          其他:若使用的是腳手架工具搭建的項(xiàng)目,會(huì)自帶eslint配置(eslintConfig)。prettier 和 eslint 會(huì)有一些配置上的沖突,這個(gè)時(shí)候需要安裝eslint-config-prettier[9] 以使 ESLint 和 Prettier 相互配合,安裝完后在.eslintrc中配置(以Create-React-App為例):

          ??"eslintConfig":?{
          ????"extends":?[
          ??????"react-app",
          ??????"react-app/jest",
          ??????"prettier"
          ????]
          ??},
          復(fù)制代碼

          這樣就可以用"prettier"的部分規(guī)則覆蓋前面的規(guī)則,讓它們都能正常工作。

          更多詳情見:Prettier[10]。

          3. 代碼規(guī)范之JS/TS規(guī)范

          JS/TS主流的大致有這幾種:

          • Airbnb JavaScript Style Guide[11]
          • Google JavaScript Style Guide[12]
          • Idiomatic JavaScript Style Guide[13]
          • JavaScript Standard Style Guide[14]
          • jQuery JavaScript Style Guide[15]

          比較推薦使用 Airbnb JavaScript Style Guide,它在 Github 上足有 12萬 star,幾乎覆蓋了 JavaScript 的每一項(xiàng)特性。

          具體配置:

          1). 安裝依賴

          npm?install?eslint?--save-dev
          //?or
          yarn?add?eslint?--dev
          復(fù)制代碼

          2). 生成配置文件

          npm?init?@eslint/config
          //?or
          yarn?create?@eslint/config
          復(fù)制代碼

          跟著終端中的提示,按照自身需求一步步選擇即可。

          有了具體的規(guī)范后,我們同樣需要使用工具去約束:還是通過在git commit階段校驗(yàn),若不通過則取消提交。

          配置(還是在 package.json 中的 lint-staged ):

          ??"lint-staged":?{
          ????"**/*":?"prettier?--write?--ignore-unknown",?//格式化
          ????"src/*":?"eslint?--ext?.js,.ts,.tsx"??//進(jìn)行eslint校驗(yàn)
          ??},
          復(fù)制代碼

          注意:這里如果選用的Typescript,則會(huì)默認(rèn)使用@typescript-eslint/parser解析器,官方為了追求更快的解析速度,并不會(huì)對(duì).ts文件中的類型進(jìn)行檢查,只會(huì)做語(yǔ)法檢測(cè)。

          如果需要對(duì)類型也進(jìn)行檢測(cè),需要在extends中加上plugin:\@typescript-eslint/recommended-requiring-type-checking[16]。

          但是在筆者的使用中發(fā)現(xiàn)效果并不好,一些基本的類型依然檢測(cè)不出來,索性這里換了另一種方式:在pre commit 中執(zhí)行yarn run tsc,這里的意思是對(duì)項(xiàng)目中ts文件進(jìn)行類型檢測(cè),默認(rèn)會(huì)讀取根目錄中的tsconfig.json配置。

          這種方式并不完美,它的弊端就在于全量檢測(cè),如果項(xiàng)目不大還好,若是項(xiàng)目代碼量夠多,檢測(cè)10-20s也是常有的事。

          更多詳情查看eslint官網(wǎng):eslint.org/docs/user-g…[17]

          4. 代碼規(guī)范之CSS規(guī)范

          CSS檢查代碼規(guī)范使用?stylelint?插件,規(guī)范則推薦使用 stylelint-config-standard[18]

          1). 安裝

          npm?install?--save-dev?stylelint?stylelint-config-standard
          復(fù)制代碼

          2).?在項(xiàng)目的根目錄中創(chuàng)建一個(gè)配置文件.stylelintrc.json,內(nèi)容如下:

          {
          ??"extends":?"stylelint-config-standard"
          }
          復(fù)制代碼

          3). 解決與prettier配置的沖突:

          npm?install?--save-dev?stylelint-config-prettier
          復(fù)制代碼

          4). 將下面配置復(fù)制到.stylelintrc.json中:

          {
          ??"extends":?["stylelint-config-standard",?"stylelint-config-prettier"]
          }
          復(fù)制代碼

          5). 在 git commitv階段進(jìn)行檢測(cè):

          ?"lint-staged":?{
          ????"**/*":?"prettier?--write?--ignore-unknown",?//格式化
          ????"src/**.{js,jsx,ts,tsx}":?"eslint?--ext?.js,.jsx,.ts,.tsx",?//對(duì)js文件檢測(cè)
          ????"**/*.{less,css}":?"stylelint?--fix"?//對(duì)css文件進(jìn)行檢測(cè)
          ??},
          復(fù)制代碼

          5. 代碼規(guī)范之自定義其他規(guī)范

          下面列一些團(tuán)隊(duì)內(nèi)定的其他規(guī)范:

          (1)命名規(guī)范

          變量的命名中應(yīng)盡量減少縮寫的情況發(fā)生,做到見名知意。

          //????自我感覺良好的縮寫:
          let?rContent?=?'willen';?

          //????無需對(duì)每個(gè)變量都寫注釋,從名字上就看懂
          let?firstName?=?'jackie';?

          //????從命名無法知道返回值類型
          function?showFriendsList()?{....}?//?//?無法辨別函數(shù)意圖,返回的是一個(gè)數(shù)組,還是一個(gè)對(duì)象,還是true?or?false?

          //????明確函數(shù)意圖,對(duì)于返回true?or?false的函數(shù),最好以should/is/can/has開頭
          function?shouldShowFriendsList()?{...}
          function?isEmpty()?{...}
          function?canCreateDocuments()?{...}
          function?hasLicense()?{...}
          function?sendEmailToUser(user)?{....?}?//動(dòng)詞開頭,函數(shù)意圖就很明顯
          復(fù)制代碼

          (2)寫注釋

          在每個(gè)文件的頂部明確說明該組件做什么,有沒有業(yè)務(wù)理解難點(diǎn)等等,對(duì)業(yè)務(wù)特殊函數(shù)/變量也需要寫注釋

          /**
          ?*?導(dǎo)航頁(yè)面-右邊區(qū)域
          ?*/

          ?
          const?Content=>()=>xxx
          ?
          const?MAX_INPUT_LENGTH?=?8;?//用于限制密碼輸入框

          function?Component(props)?{
          ??return?(
          ????<>
          ??????{/*?如果用戶沒有訂閱則不展示廣告?*/}
          ??????{user.subscribed???null?:?<SubscriptionPlans?/>}
          ????

          ??)
          }
          ?
          復(fù)制代碼

          (3)變量兜底

          //????對(duì)于求值獲取的變量,沒有兜底
          const?{?data?}?=?getApiRequest();
          data.map((s)?=>?s.id);?//沒有考慮data異常的情況,代碼一跑就爆炸

          //????對(duì)于求值變量,做好兜底
          const?{?data?=?[]?}?=?getApiRequest();
          data.map((s)?=>?s?.id);?//沒有考慮data異常的情況,代碼一跑就爆炸
          復(fù)制代碼

          (4)輔助函數(shù)必須是純函數(shù)

          //????不要讓功能函數(shù)的輸出變化無常
          function?plusAbc(a,?b,?c)?{??//?這個(gè)函數(shù)的輸出將變化無常,因?yàn)閍pi返回的值一旦改變,同樣輸入函數(shù)的a,b,c的值,但函數(shù)返回的結(jié)果卻不一定相同。
          ??var?c?=?fetch('../api');
          ??return?a+b+c;
          }

          //????功能函數(shù)使用純函數(shù),輸入一致,輸出結(jié)果永遠(yuǎn)唯一
          function?plusAbc(a,?b,?c)?{??//?同樣輸入函數(shù)的a,b,c的值,但函數(shù)返回的結(jié)果永遠(yuǎn)相同。
          ??return?a+b+c;
          }
          復(fù)制代碼

          (5)優(yōu)先使用函數(shù)式編程

          //????使用for循環(huán)編程
          for(i?=?1;?i?<=?10;?i++)?{
          ???a[i]?=?a[i]?+1;
          }

          //????使用函數(shù)式編程
          let?b?=?a.map(item?=>?++item)
          復(fù)制代碼

          (6)優(yōu)先使用函數(shù)式組件

          除非需要用到錯(cuò)誤邊界,否則函數(shù)式組件應(yīng)該是首選方法。

          (7)組件復(fù)雜度

          如果一個(gè)組件做的事情太多,應(yīng)適當(dāng)提取一些邏輯,將其拆分為更小的組件。

          如果提取的組件很復(fù)雜,則需要依照一定的規(guī)則和條件一一提取它。

          代碼行數(shù)并不是一個(gè)客觀的衡量標(biāo)準(zhǔn),更多是需要考慮責(zé)任劃分和抽象。

          (8)用錯(cuò)誤邊界

          當(dāng)需要對(duì)大量數(shù)據(jù)進(jìn)行渲染處理時(shí),需要通過錯(cuò)誤邊界組件對(duì)其進(jìn)行降級(jí)處理。

          更多詳情見之前寫的專題文章:淺析前端異常及降級(jí)處理[19] 。

          function?Component()?{
          ??return?(
          ????<Layout>
          ??????<ErrorBoundary>
          ????????<CardWidget?/>
          ??????ErrorBoundary>


          ??????<ErrorBoundary>
          ????????<FiltersWidget?/>
          ??????ErrorBoundary>

          ??????<div>
          ????????<ErrorBoundary>
          ??????????<ProductList?/>
          ????????ErrorBoundary>
          ??????div>
          ????Layout>
          ??)
          }
          復(fù)制代碼

          (9)props參數(shù)傳遞

          props一層層傳遞一直是我們很頭疼的一個(gè)問題,最核心的問題是不清楚props是從哪個(gè)初始組件傳來的,以及props中到底有哪些東西,上下文是什么?

          因此對(duì)于傳遞較深的場(chǎng)景我推薦直接使用 context,對(duì)于 props 中的內(nèi)容和上下文通過 TS 來解決。

          //?A.tsx
          interface?AProps?{
          ??param:?string;
          }
          const?A?=?({?param?}:?AProps)?=>?{
          ??return?<B?param?=?{param}?/>;
          };

          //????上下文清晰
          //?B.tsx
          const?B?=?({?param?}:?{?param:?AProps['param']?})?=>?{
          ??return?<div>hello?worlddiv>;
          };

          復(fù)制代碼

          (10)props傳參數(shù)量

          如果超過 5 個(gè)props,就該考慮是否拆分該組件。在某些情況下,這是需要對(duì)組件進(jìn)行重構(gòu)的標(biāo)志。

          注意:組件使用的props越多,重新渲染的理由就越多。

          (11)避免嵌套三元運(yùn)算符

          三元運(yùn)算符在第一級(jí)之后變得難以閱讀,雖然看起來節(jié)省了代碼空間,但最好在代碼中明確意圖,保持良好的閱讀性。

          //????不夠清晰,要是再嵌套一層兩層呢
          isSubscribed???(
          ??<ArticleRecommendations?/>
          )?:?isRegistered???(
          ??<SubscribeCallToAction?/>
          )?:?(
          ??<RegisterCallToAction?/>
          )

          //????將判斷邏輯進(jìn)行拆分
          function?CallToActionWidget({?subscribed,?registered?})?{
          ??if?(subscribed)?{
          ????return?<ArticleRecommendations?/>
          ??}

          ??if?(registered)?{
          ????return?<SubscribeCallToAction?/>
          ??}

          ??return?<RegisterCallToAction?/>
          }

          function?Component()?{
          ??return?(
          ????<CallToActionWidget
          ??????subscribed={subscribed}
          ??????registered={registered}
          ????/>

          ??)
          }
          復(fù)制代碼

          (12)將列表組件封裝成獨(dú)立組件

          //????列表渲染和其他邏輯雜糅在一起
          function?Component({?topic,?page,?articles,?onNextPage?})?{
          ??return?(
          ????<div>
          ??????<h1>{topic}h1>

          ??????{articles.map(article?=>?(
          ????????<div>
          ??????????<h3>{article.title}h3>
          ??????????<p>{article.teaser}p>
          ??????????<img?src={article.image}?/>
          ????????div>
          ??????))}
          ??????<div>You?are?on?page?{page}div>
          ??????<button?onClick={onNextPage}>Nextbutton>
          ????div>
          ??)
          }

          //????將列表組件提取出來,一目了然
          function?Component({?topic,?page,?articles,?onNextPage?})?{
          ??return?(
          ????<div>
          ??????<h1>{topic}h1>

          ??????<ArticlesList?articles={articles}?/>
          ??????<div>You?are?on?page?{page}div>
          ??????<button?onClick={onNextPage}>Nextbutton>
          ????div>
          ??)
          }
          復(fù)制代碼

          (13)避免嵌套渲染函數(shù)

          //????不要將其定義在渲染函數(shù)組件中
          function?Component()?{
          ??function?renderHeader()?{
          ????return?<header>...header>
          ??}
          ??return?<div>{renderHeader()}div>
          }

          //????將其抽離到獨(dú)立的組件中去
          import?Header?from?'@modules/common/components/Header'

          function?Component()?{
          ??return?(
          ????<div>
          ??????<Header?/>
          ????div>

          ??)
          }
          復(fù)制代碼

          (14)組件/函數(shù)導(dǎo)入導(dǎo)出

          //????在文件頭部導(dǎo)入,順序依次為:?第三方庫(kù)?>?公共組件/方法?>?非公共部分組件/方法
          import?React?from?'react'
          import?_?from?'loadsh'
          import?Header?from?'@components/header'
          import?Content?from?'./Content'

          //????在底部導(dǎo)出
          export?{?Content,?Header?}
          export?default?Component
          復(fù)制代碼

          ...

          6. 項(xiàng)目文件結(jié)構(gòu)規(guī)范

          不得不說,在這件事上我們團(tuán)隊(duì)曾經(jīng)花費(fèi)了大量的經(jīng)歷去思考和實(shí)踐,也是信了React官方的鬼話:不要花超過五分鐘在選擇項(xiàng)目文件組織結(jié)構(gòu)上[20]。

          在項(xiàng)目初期若不重視,到了后期就是到處天馬行空,你很難在期望的目錄下找到你想要的文件。

          文件夾名稱全部采用小寫 + "-" 來隔開,index.ts更多是用來做導(dǎo)出作用,要不然最后編輯器中滿屏的index.tsx,很難區(qū)分。

          ???-?src?開發(fā)目錄
          ??????-?pages?視圖
          ??????????-?module-a?模塊A
          ????????????-?components?私有組件
          ??????????????-?ComA.tsx
          ??????????????-?ComB.tsx
          ????????????-?index.module.less
          ????????????-?index.tsx
          ????????????-?Content.tsx
          ??????????-?module-b?模塊B
          ??????-?components?公共組件
          ????????-?index.ts?導(dǎo)出所有組件
          ????????-?header
          ??????????-?index.tsx
          ??????????-?index.module.less
          ??????????-?User.tsx
          ??????????-?useGetBaseInfo.hooks.ts
          ??????-?routers?路由文件
          ??????-?store?redux中的數(shù)據(jù)
          ??????-?utils?這里是以u(píng)tils為后綴
          ????????-?index.ts
          ????????-?a.utils.ts
          ????????-?b.utils.ts
          ??????-?hooks?這里是以hooks為后綴
          ????????-?index.ts
          ????????-?a.hooks.ts
          ????????-?b.hooks.ts
          ??????-?styles?靜態(tài)資源文件
          ??????-?service?api請(qǐng)求,這里是以api為后綴
          ????????-?a.api.ts?按照后端微服務(wù)進(jìn)行劃分
          ????????-?b.api.ts
          ??????-?constans?常量
          復(fù)制代碼

          通過對(duì)工具函數(shù)、hooks、api 等加上后綴,更加容易區(qū)分引入的文件。

          7. Git commit規(guī)范

          git commit 規(guī)范主要可以幫助開發(fā)人員在 code review 期間更容易理解提交的內(nèi)容,現(xiàn)在大部分主流 commit 規(guī)范都是基于Angular 團(tuán)隊(duì)的規(guī)范[21]而衍生出來的,它的 message 格式如下:

          ():?




          復(fù)制代碼

          每個(gè)提交消息都包含一個(gè)subject、一個(gè)body和一個(gè)footer (中間使用空行分割),提交信息的任何一行不能超過 100 個(gè)字符。

          ?? type主要有以下幾種類型:

          • feat: 一個(gè)新特性
          • fix: 修復(fù)bug
          • docs: 文檔修改
          • style: 不影響代碼含義的更改(空格、格式、缺少分號(hào)等)
          • refactor: 代碼重構(gòu)
          • perf: 優(yōu)化性能
          • test: 測(cè)試用例修改
          • chore: 對(duì)構(gòu)建過程或輔助工具和庫(kù)的更改,例如文檔生成

          ?? scope:可以是影響范圍的任何內(nèi)容。

          ?? subject:包含對(duì)更改的簡(jiǎn)潔描述,規(guī)則:

          • 使用陳述語(yǔ)句
          • 第一個(gè)字母不要大寫
          • 末尾沒有點(diǎn) (.)

          ?? body:commit 具體修改內(nèi)容, 可以分為多行,應(yīng)該包括改變的動(dòng)機(jī),并與以前的行為進(jìn)行對(duì)比。

          ?? footer: 一些備注, 通常是修復(fù)的 bug 的鏈接。

          截取一張開源庫(kù)的 commit,example[22]

          image.png

          有了規(guī)范后,我們需要通過工具去約束:commitlint[23]。它要做的就是在我們每次提交 git commit 的時(shí)候,都會(huì)幫我們檢查 commit message 是否符合一定的規(guī)范,如果不符合,就讓這次提交失敗。

          具體配置:

          #?安裝?commitlint?cli?和?conventional?config
          npm?install?--save-dev?@commitlint/{config-conventional,cli}
          #?Windows:
          npm?install?--save-dev?@commitlint/config-conventional?@commitlint/cli

          配置要使用的?commitlint?規(guī)則
          echo?"module.exports?=?{extends:?['@commitlint/config-conventional']}"?>?commitlint.config.js

          加入到husky中:
          npx?husky?add?.husky/commit-msg?'npx?--no?--?commitlint?--edit?"$1"'
          or
          yarn?husky?add?.husky/commit-msg?'yarn?commitlint?--edit?$1'
          復(fù)制代碼

          更多詳情見官網(wǎng):github.com/conventiona…[24]

          8. UI設(shè)計(jì)規(guī)范

          優(yōu)秀的開發(fā)者應(yīng)該反向推動(dòng)UI的規(guī)范,并且能夠支撐UI規(guī)范的落地。

          UI 規(guī)范的最大好處就是能夠提質(zhì)提效:

          • 在開發(fā)者的角度,與設(shè)計(jì)規(guī)范同步形成研發(fā)資產(chǎn),避免重復(fù)造輪子;
          • 在測(cè)試的角度,能夠避免重復(fù)的無意義走查;
          • 在UI設(shè)計(jì)師的角度,減少設(shè)計(jì)成本,提高設(shè)計(jì)效率,可以快速承接新需求;
          • 站在產(chǎn)品角度,提高產(chǎn)品迭代與優(yōu)化效率,降低試錯(cuò)成本;
          • 站在用戶角度,解決用戶體驗(yàn)一致性。

          那到底應(yīng)該怎么去推動(dòng)UI規(guī)范?我的做法是先讓設(shè)計(jì)師去給出一系列的規(guī)范,沒有相關(guān)規(guī)范就拉上產(chǎn)品經(jīng)理一起制定規(guī)范。然后前端建立一套自己的組件庫(kù),再將組件庫(kù)提供給UI設(shè)計(jì)師,以此來相互監(jiān)督是否達(dá)成了規(guī)范協(xié)議。

          具體參考 Antd設(shè)計(jì)規(guī)范[25]。

          總結(jié)

          統(tǒng)一規(guī)范的最根本目的是為了保證團(tuán)隊(duì)成員的一致性,從而減少溝通成本,提高開發(fā)效率。

          學(xué)會(huì)熱愛標(biāo)準(zhǔn),但要確保它們不是一成不變的。如果制定的規(guī)范不適合您的團(tuán)隊(duì),請(qǐng)確保可以適應(yīng)和重寫所需要的任何規(guī)則。它并不是要強(qiáng)制執(zhí)行一種工作方式,而是為了幫助促進(jìn)團(tuán)隊(duì)之間的互動(dòng) ??????。

          最后

          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
          回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會(huì)很認(rèn)真的解答喲!
          回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對(duì)你有幫助,在看」是最大的支持
          ?》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持


          瀏覽 30
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色三级片视频 | 免费视频二区三区 | 国产不卡免费视频 | 操片免费| 俺去啦最新地址 |