淺談前端組件發(fā)布自動(dòng)化

淺談前端組件發(fā)布自動(dòng)化

從09年angularJS被谷歌推出以來(lái),涌現(xiàn)了很多前端應(yīng)用的開(kāi)發(fā)、設(shè)計(jì)等方面優(yōu)秀的解決方案(框架 、庫(kù)、設(shè)計(jì)規(guī)范)。隨著SPA的普及,"Web Components"的設(shè)計(jì)標(biāo)準(zhǔn)漸漸開(kāi)始影響各個(gè)框架的設(shè)計(jì)方向,開(kāi)發(fā)人員的邏輯封裝也不再像以前效率相對(duì)低下,優(yōu)秀的框架給開(kāi)發(fā)者提供了簡(jiǎn)潔且快速的組件化解決方案。

本文會(huì)盡量少的貼代碼,盡量少的談及工程化本身的東西,旨在分享組件自動(dòng)化基礎(chǔ)設(shè)施建設(shè)過(guò)程中的些許經(jīng)驗(yàn)。

工程化的內(nèi)容后續(xù)會(huì)有單獨(dú)的“毒文”來(lái)禍害大家。

一、應(yīng)用背景

如上所述,中大型的團(tuán)隊(duì)或公司在未來(lái)的一段時(shí)間,都需要封裝足夠多且完善的UI組件來(lái)支撐快速開(kāi)發(fā)降低學(xué)習(xí)成本。這樣的情境下,就會(huì)有一些人,去進(jìn)行組件的標(biāo)準(zhǔn)化開(kāi)發(fā),快速迭代,而隨之而來(lái)且亟待解決的問(wèn)題:

  • 組件的版本控制
  • 組件的產(chǎn)出物(包、文檔)的相關(guān)性
  • 組件構(gòu)建、測(cè)試的冗長(zhǎng)的工作量
  • 組件發(fā)布環(huán)節(jié)的不可控
  • 權(quán)限的不可控性(組件倉(cāng)庫(kù)權(quán)限、源碼倉(cāng)庫(kù)權(quán)限)

組件發(fā)布自動(dòng)化的目的不僅僅是減少你的手動(dòng)構(gòu)建、發(fā)布的工作量,它的本質(zhì)是對(duì)多人協(xié)同組件開(kāi)發(fā)方式的規(guī)范和管控。

沒(méi)有這些你的前端研發(fā)工作也能支撐?能用和好用是兩個(gè)概念。

二、涉眾及相關(guān)技術(shù)棧

1、人員涉眾

  • 開(kāi)發(fā)人員:組件開(kāi)發(fā)者,源碼的提交者
  • 配置管理員:版本發(fā)布的流程、權(quán)限控制者,同時(shí)也是發(fā)布節(jié)奏的控制者

2、相關(guān)技術(shù)名詞

了解以下,閱讀過(guò)程會(huì)相對(duì)輕松:

  • nodeJS:自動(dòng)化流程中的主要參與者
  • gradle:負(fù)責(zé)整體流程的包裝,同時(shí)也會(huì)用到其生態(tài)中的一些插件
  • jenkinsFile:推薦用聲明式(groovy),本文基于腳本式
  • webdav:用來(lái)做文檔發(fā)布的服務(wù)器(優(yōu)勢(shì)是可控的發(fā)布權(quán)限),可以用其他web容器替代

3、工程職責(zé)

為了詳略得當(dāng),這里列舉工程的一些基礎(chǔ)功能(這里默認(rèn)已經(jīng)實(shí)現(xiàn),實(shí)際需要我們自己根據(jù)我們的實(shí)際情況去實(shí)現(xiàn)),以免贅述與本文不相關(guān)的內(nèi)容。

  1. 包輸出:工程提供構(gòu)建的基礎(chǔ)功能(將源碼輸出為npm倉(cāng)庫(kù)的package的功能)
  2. 文檔輸出:工程提供文檔輸出的功能(推薦markdown手寫合成的體驗(yàn)較好的文檔輸出機(jī)制)
  3. 測(cè)試:提供單元或e2e測(cè)試的基礎(chǔ)框架

三、流程概覽

自動(dòng)化流程.png

如上圖所示,發(fā)布流程主要為(區(qū)別化的內(nèi)容加粗):

  1. 開(kāi)發(fā)人員提交代碼(git push)/配置管理員打tag
  2. git接到push/tag,根據(jù)配置好的webhook給jenkins發(fā)請(qǐng)求
  3. jenkins接收請(qǐng)求并觸發(fā)指定的task,根據(jù)jenkinsFile執(zhí)行pipeline:
    • 更新項(xiàng)目并檢查設(shè)置
    • sonar:推送代碼到sonar
    • 測(cè)試:?jiǎn)卧獪y(cè)試&&e2e測(cè)試
    • package構(gòu)建
    • package發(fā)布:計(jì)算版本號(hào)并發(fā)布package
      • 根據(jù)git 的最后一條log計(jì)算下一版本號(hào)
      • 根據(jù)git的最后一條log區(qū)分發(fā)布測(cè)試版本(snapshots)還是正式版本(release)
    • 構(gòu)建doc
    • 發(fā)布doc:根據(jù)git的最后一條log區(qū)分發(fā)布測(cè)試版本文檔(snapshots)還是正式版本文檔(release)

四、流程詳述(冗長(zhǎng)的細(xì)節(jié),可略)

1、update project - 更新項(xiàng)目并檢查設(shè)置

echo 'update source'
checkout scm
echo 'reset config'
sh './gradlew widget-pkg-reset-config -q'
echo 'update dependencies'
sh 'npm install && npm update'
  • 更新(初始化)源碼:jenkins行為,更新項(xiàng)目源碼checkout SCM (也可用gradle或node執(zhí)行代碼更新)
  • 更新(初始化)gradle依賴:gradle行為,根據(jù)gradle配置,更新gradle相關(guān)依賴
  • 更新(初始化)npm依賴:node行為,根據(jù)pkg版本,更新相關(guān)依賴(可能為運(yùn)行時(shí)依賴,也可能為開(kāi)發(fā)時(shí)依賴)
  • 檢查配置: gradle包裝(node行為),檢查當(dāng)前構(gòu)建環(huán)境的正確性,如當(dāng)前所需的環(huán)境變量、當(dāng)前所設(shè)置的倉(cāng)儲(chǔ)地址、當(dāng)前所需要的所有構(gòu)建環(huán)境的版本等,如缺失則發(fā)出警告并中斷集成,如不正確則重置正確環(huán)境設(shè)置。

2、test - 測(cè)試

暫略。

3、build source - 構(gòu)建資源

echo 'Building source..'
sh 'npm run pre-release'
echo 'Build source completed'
  • 構(gòu)建資源:node行為,進(jìn)行資源構(gòu)建。

4、publish source

sh './gradlew widget-pkg-modify-version -q'
sh './gradlew widget-pkg-set-config -q'
echo 'Publish source..'
sh 'npm run publish-to-npm'
  • 修改版本號(hào): gradle包裝(node行為),根據(jù)插件計(jì)算出的currentVersion,臨時(shí)修改當(dāng)前構(gòu)建結(jié)果中的package.json文件的version字段。
  • 設(shè)置相關(guān)發(fā)布配置:gradle包裝(node行為)。
    • 根據(jù)當(dāng)前版本狀態(tài)選擇發(fā)布的倉(cāng)庫(kù)
    • 根據(jù)當(dāng)前環(huán)境變量設(shè)置當(dāng)前發(fā)布倉(cāng)儲(chǔ)的認(rèn)證信息
  • 發(fā)布資源:node行為,發(fā)布構(gòu)建資源。

5、build doc

echo 'Building doc..'
sh 'npm run build'
echo 'Build doc completed'
  • 構(gòu)建資源:node行為:構(gòu)建當(dāng)前使用手冊(cè)

6、publish doc

echo 'Publish doc..'
sh './gradlew widget-docs-publish -q'
echo 'source doc completed'
  • 清除已發(fā)布文擋:gradle行為,嘗試清除已經(jīng)發(fā)布在webdav上的當(dāng)前版本文檔(為了防止文擋重復(fù)發(fā)布的文件冗余,因?yàn)榍岸遂o態(tài)有文件名有MD5后綴,重復(fù)發(fā)布無(wú)法覆蓋)。
  • 修改文擋資源的BASE:gradle包裝(node行為),根據(jù)文擋發(fā)布需要,在webdav的服務(wù)目錄下,文件夾深度決定url上下文層級(jí),構(gòu)建后的靜態(tài)為angular工程,需要上下文,否則無(wú)法正常調(diào)用web history,所以需要根據(jù)當(dāng)前的currentVersion修改當(dāng)前文檔資源的base href。
  • 發(fā)布文檔:gradle行為,調(diào)用gradle插件進(jìn)行遞歸發(fā)布。

五、專項(xiàng)剖析

1、不同層級(jí)的行為及調(diào)用關(guān)系分析

行為及調(diào)用關(guān)系分析.png

2、版本的計(jì)算

2.1、版本發(fā)布到正式、測(cè)試倉(cāng)庫(kù)的判斷規(guī)則

檢查當(dāng)前倉(cāng)儲(chǔ)的最后一次行為(git log):

  • 如果沒(méi)有tag,版本從0.1.0-SNAPSHOT開(kāi)始
  • 如果有tag,但最新的commit不是tag,則根據(jù)語(yǔ)義規(guī)范發(fā)布相應(yīng)版本的SNAPSHOT版本
  • 如果有tag,且最新的commit是tag,則根據(jù)tag發(fā)布
2.2、版本遞增計(jì)算規(guī)則

請(qǐng)綜合參照:

3、如何指定版本號(hào)發(fā)布

在發(fā)布時(shí)遇到的一個(gè)問(wèn)題,java的包發(fā)布的版本可以通過(guò)gradle變量來(lái)指定,那前端的package的版本號(hào)如何動(dòng)態(tài)指定?在npm文檔搜索無(wú)果后,決定寫插件去修改“package.json”的version來(lái)指定發(fā)布版本。

為了避免導(dǎo)致其他問(wèn)題,建議在初始化的步驟將“package.json”進(jìn)行checkout。

五、總結(jié)和思考

1、如何在“簡(jiǎn)化技術(shù)棧”與“前后端自動(dòng)化統(tǒng)一”上做出取舍?

這其中的一個(gè)關(guān)鍵點(diǎn)為,前端自動(dòng)化為什么要使用gradle。

在本文的實(shí)踐中,受我們團(tuán)隊(duì)已經(jīng)存在后端的自動(dòng)化工作流的影響,為了與其統(tǒng)一版本的升級(jí)規(guī)則,會(huì)用到gradle的“axion-release-plugin”插件,以及在發(fā)布到webdav時(shí)會(huì)用到“uk.co.firstzero.webdav”,出于前后端統(tǒng)一和不重復(fù)造輪子考慮,前端才增加gradle的使用。

那么我們不用gradle可以嗎?當(dāng)然可以,你只需要以上提到的內(nèi)容用node再造一遍輪子,祝你好運(yùn)。

送一個(gè)版本計(jì)算的node輪子(不再更新,但可供參考):axion-release-node-plugin

2、前端有各種lint,sonar相對(duì)前端的意義大嗎?

后續(xù)補(bǔ)充。

最后編輯于
?著作權(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)容