- read

成為前端建築師吧!透過 Frontend Infra 為前端應用打造穩健且高效率的開發體驗

莫力全 Kyle Mo 75

什麼是 Frontend Infrastructure (Infra) ?

提到前端網頁開發,可能很多人聯想到的都是 UI 畫面切版、動畫特效,甚至認為前端開發者的工作內容「離不開畫面」。但其實前端開發是一個非常廣的領域,同樣身為前端工程師,每個人專注開發的領域可能都不一樣,所打造出的技能樹也會長成不同的形狀。而我自己比較感興趣的是前端開發基礎建設 (infrastructure) 相關的議題,那到底哪些技術屬於前端基礎建設的範疇呢?

其實在蠻久之前,我寫過一篇關於 Frontend Infra 的簡短文章,但那時自己只是覺得這個前端領域中的分支看起來很酷,並沒有太深入的理解,在自己實際加入企業中的 Web Frontend Infra Team 並研究了許多有趣的主題之後,我想針對這個題目我有了不同的體悟,因此決定結合過去的經驗,重新整理一下我對於 Frontend Infra 的認知與想法。

首先我們先看看 ChatGPT 對於 Frontend Infrastructure 的理解是什麼(現在很多工程師對於 AI 的回答甚至都超越對人的信任了🤣):

可以發現因為 Frontend Infra 並不是一個有被明確定義的名詞,所以其實各種前端相關的技術都可以被歸類在其中,例如效能優化、CI / CD、Bundler…等等都可以算是 Frontend Infra 的範疇,基本上它的具體內容以及定義會根據組織、團隊與個人的需求和目標而有所不同。

雖說如此,社群中對於這個名詞,還是有一個較為普遍的定義:

Frontend Infra 這個詞通常被用來描述為了提升「開發效率」和「產品品質」而導入的一套系統、流程或工具,並且常常包括一些關於如何使用這些工具和系統的最佳實踐或標準。

這個定義各位讀者可以先稍微記住,我們在最後會再回顧一次。

回到上方 ChatGPT 的回答,我們可以發現它說對於「大規模」的組織來說,前端基礎設施是很重要的,這是為什麼呢?

管理多個前端專案

對於大型組織來說,同時有多個前端專案要開發與維護是很常見的事,除了給客戶(有可能是 2C,也有可能是 2B)使用的專案以外,也可能會有給企業人員使用的內部系統,這時面對要同時管理多個前端專案的狀況,採用什麼方式會比較有效率呢?

我們當然可以個別看待每一個專案,從頭打造每一個 codebase、選用不同的 Tech Stack,並個別發展屬於該專案的標準(例如 testing guideline)與基礎建設(例如 CI/CD Pipeline)。不過採用這種方式你可能會發現一個問題:

我們違反了 DRY (Don’t Repeat Yourself)原則,一直在做重複的事情。

面對這種狀況,有些企業會選擇獨立出一個專門的團隊來協助打造前端的基礎建設,這個團隊的目標通常會包含以下主題:

1. Boilerplate (Generator)

通常在專案的最初期會需要選擇適合這個專案需求的 tech stack,例如要使用 React 還是 Vue ? 需不需要採用 SSR 的框架例如 Next.js 或是 Nuxt.js ? 在決定要使用的技術後,我們可以選擇從頭開始建立開發的環境,例如一個一個安裝需要使用的套件,從頭開始撰寫 linting 的 rule config,不過為了節省時間,我們也可以選擇使用別人寫好的 boilerplate template,例如 create-react-app 或者 Vue Cli,基本上只要在 terminal 下幾行指令就可以快速建構出架構算蠻完整的專案。不過這些由官方提供的 template 有時候並沒辦法完全符合企業所想要複用的功能,因此有些公司會選擇建構自己的 template,來達成更客製化的需求。

使用 template 的好處是可以更快速的建立專案環境,不過它仍舊有一些成本在,例如維護 template 的成本、依賴 template 的情況下比較難導入新技術(例如原本的 template 已經整合了 Redux 來處理 state management,這時候如果想要更換其他的 state management 套件會需要花費額外的工)…等等,因此在使用 template 前同樣需要謹慎評估一下。

2. Sharing Code

當我們在開發上累積比較多經驗後,應該都會理解共享程式碼以避免重複撰寫相同邏輯的概念,也就是所謂的 Sharing Code。而 Sharing Code 其實有非常多種方式,小至把共用的 util functions 拆分到其他檔案,大至如果要在不同的專案間共享程式碼時,可以考慮使用 public 或是 private 的 npm 來管理,又或是在 monorepo 架構下可以拆分成獨立的 package 來供 repo 中的不同專案使用。

當然幾乎任何方法的背後都帶著風險成本,如果只有一個專案,要修改 code 其實相當方便,不用怕去影響到其他專案,不過如果是在不同專案間共用程式碼,就必須用更嚴格的標準確保程式碼的品質,同時讓程式碼更具備彈性與可重用性,在測試上也必須變的更加強健。因此就算開發一樣的功能,要思考重用性就會讓開發與維護的成本增加許多。另外版本控制也會是一項難題,在不是使用 monorepo 而是 private npm 的狀況,要如何確保每個專案都能盡量跟到 Sharing Code 最新的版本且不能造成毀滅性的 breaking change,是個耗廢心力的難題。

3. Design System

現代的前端開發主要都是以元件化開發為主,你一定曾經遇過在不同的專案中需要使用功能與樣式都差不多的元件(例如 button),這時候你可能會需要可以「Sharing Design」,而 Design System 就是常見的 solution。

而前端開發者可以進一步依照 Design System 實作出 component library,可以依照需求使用 Vue、React,又或者是你有跨框架共用的需求,也可以考慮使用 Web Component 來實作。這其實也算是一種「Sharing Code 」的方式,所以同樣會具有第二點 Sharing Code 的優缺點,不過它也帶來一些額外的限制,例如更嚴格的「設計」準則、比較缺失彈性的樣式設計風格…等等。

4. Unified CI/CD Infra

專案在完成開發後通常會需要經過 building 與 testing 來驗證程式碼的品質與正確性,在經過嚴格的檢驗後才能被 deploy 上線,而通常這些步驟都會透過 CI/CD pipeline 自動化。在擁有多個專案的情況下,為每個專案獨自建立一個 CI/CD pipeline 當然是一個選擇(目前待過的公司也都是這樣用),不過也有另一種方式是建立一個 Unified CI/CD Infra,讓各專案的開發者可以不用花太多工在建立 pipeline 上,而由 Infra 團隊負責這些 pipeline 的建立與維護。

採用 unified infra 的風險大概就是 reliability 了,統一管理 pipeline 其實也帶出 single point of failure 的風險,萬一今天 infra 炸掉了可能會阻礙每個專案開發或發佈的流程。

除了上述 One Pipeline 的方式,也有的團隊會讓每個專案擁有各自的 CI/CD Pipeline,但卻遵循著一致的流程與標準,確保所有前端專案都有高品質、一致的開發、測試和部署流程。

5. Deploying & Serving

經過 CI/CD 的驗證後網站最終就可以被 host 上線啦!我們當然不希望自己租一台主機再把網站相關檔案搬過去上線(可以,只是很麻煩),更何況還要設置 CDN 等等機制,目前來說最方便的方式應該就是尋求雲端解決方案了(Cloud),這種方式的風險無疑就是雲端服務商的可靠性,萬一今天雲端服務商出事了,連帶的可能會影響到底下千千萬萬個服務。

6. Monitoring

在前端專案中,我們經常會結合像 Sentry、Google Analytics、Google Search Console 等工具來監控與追蹤各種指標,如錯誤訊息、使用者行為與流量、Web Vitals 等等。這樣的監控系統能助我們深入了解網站的運行狀態,並從中發現網站需要改進或修正的地方,提供了一個實證為基礎的方法來優化我們的應用。

在沒有 Frontend Infra Team 協助打造工具或制定共同準則的情況下,專案初期看似可以快速推進,不過長遠來看行進卻是緩慢的,當公司慢慢變得成熟導致專案越來越多的情況下,會出現一直重複造輪子的問題,程式碼的品質也會隨著專案數量變多而產生分歧。

有了 Frontend Infra 以後,長期來看會推進的比較快,程式碼的品質也會比較好,不過缺點是需要比較多的人力與金錢成本去做這些事,因此一般來說規模較大的企業比較適合採用獨立出一個 Frontend Infra 團隊的模式。

Web Frontend Infra Team 參與經驗分享

很幸運的,我之前剛好有參與 Web Frontend Infra 團隊的經驗,這個章節就來回顧一下我在 FE Infra Team 的日子都做了些什麼事,跟多數人普遍認為的前端工程師的職責有什麼樣的區別。

(此章節的照片皆經過後製或模擬,非當事圖片。)

我身處的 Web Frontend Infra Team 的主要職責就如上圖所示,主要有以下幾點:

  • 統一各個前端專案的 Tech Stack
  • 制定各專案間統一的開發準則
  • 開發各專案可以共用的 Packages
  • 提升前端應用的可觀測性

在這些首要目標指引下,我參與期間,團隊專注於幾個特定主題的討論:

接下來的段落會簡述一下自己參與過的主題研究。

Lighthouse CI

關於 LHCI 這個主題我其實在去年 MOPCON 年會就有作為議程主題較詳細的分享過了。透過自架 API Server 與 Database,我們把每個專案每次跑 LHCI 的結果都儲存了起來,如此一來除了可以透過 LHCI 提供的 dashboard 觀察特定專案在特定時間區間的 Lighthouse 檢測趨勢以外,也能夠比較不同次檢測的結果,將 Diff 後的資訊像上圖一樣透過 GitHub API 以 PR comments 的形式回饋給專案的開發者,讓 Lighthouse CI 可以成為前端專案的效能守門員,盡量確保不讓可能會造成使應用效能大打折扣的程式碼被 merge 進 Repo 中。

SonarQube

SonarQube 是一個程式碼檢測以及品質管理平台,Web Infra Team 花了一些時間搜集了想要 apply 在 JS/TS 專案上的規則集合,並將 SonarQube 加入到專案的 CI 流程裡,在發布 Pull Request 時它會幫我們檢測 PR 改動的檔案是不是有一些淺在的 Bug、Vulnerabilities、Security Issues、Code Smell,我們可以設定這幾項問題的總數如果超過某個數字就禁止 PR 被合併,需要修改成符合規則集合的寫法才可以通過,透過這種方式我們可以盡量避免推上一些品質不佳且跟團隊 Coding Standard 不契合的程式碼。除此之外,SonarQube 還能幫忙紀錄 Testing Coverage,在 CI 流程我們會先執行 Test 並得出測試覆蓋率的報告,將覆蓋率上傳給 SonarQube,它除了會幫我們在平台上紀錄,也會在 PR comments 中顯示該 PR 「有改動到的檔案」的測試覆蓋率,我們一樣有做了一個限制,如果 Changed Files 的測試覆蓋率沒有超過 80%,該 PR 就沒辦法 merge,透過這種方式規範團隊成員養成寫測試的習慣。

Custom ESLint Config

創建自己客製化的 ESLint Config 其實並不困難,Wen Infra Team 有自己實作給所有前端專案 Extend 的 Custom Config,這個 config 除了包含 NextJS 與 React TS 等常見的 Config 外,主要還包含了我們在 SonarQube 平台上制定出的規則集合的 Rules,希望透過這種方式,即早在 Lint 階段就檢查出一些可能會導致 SonarQube CI 報錯導致 PR 沒有辦法被 merge 的可能性,如此一來可以提升團隊的開發效率。

在搜集 SonarQube 規則對應到 ESLint 的 rules 的時候,我們發現很多規則是 ESLint 官方的 rules 沒有涵蓋到的,當然社群中很多人開發了對應 SonarQube 的 ESLint Config,但總有一些推則是沒有被 cover 到的,面對這種狀況我們可能得選擇自己實作 ESLint 的 rules,要自己實作規則需要對 AST(抽象語法樹) 有基本的理解,這會是比較困難的部分。

舉例來說,如果要寫一個限制 codebase 裡面不能出現 console.log 的規則,大概會如下:

module.exports = {
rules: {
"no-console-log": {
create: function(context) {
return {
CallExpression: function(node) {
if (node.callee.object.name === 'console' && node.callee.property.name === 'log') {
context.report(node, 'Do not use console.log()');
}
}
};
}
}
}
};

當然這個 rule 早就被 ESLint 官方 config 涵蓋了,這邊主要是表達如果有客製化的規則,都有機會自己實作喔!(參考文章

Generator

這也就是上個段落提到的 template。我們可以發現 Infra Team 其實導入了很多工具與規範,如果要每個 projects 都手動導入一遍想必會非常耗時耗力,如果有一個 project generator 可以輕鬆透過 CLI 指令就建立出一個包含 Infra Team 規範的各種工具的必要 Config 檔的專案的話,可以減少專案 kick off 的成本。因為在大型公司中建立新的專案是蠻常見的一件事,這個 generator 其實發揮蠻大的作用的。

Monitoring

前面有提到過提升前端應用的可觀測性也是 Web Infra Team 的一個重要目標,因此 Infra Team 有建立一個 Grafana 的 Dashboard,以視覺化的方式呈現每個專案的相關狀況,例如近期 PR 的 test coverage、近期 PR 違反 SonarQube rules 的數量與種類,同時在違反的數量過多時會發出警報透過 Slack 通知…等等,Infra Team可以以一個中心監管者的角度觀察每個專案的狀況,也可以提醒狀況較不好的團隊要加強注意。當然 Dashboard 還可以放入更多的資訊,例如 Web Vitals 各項指標與 Error 相關的資訊…等等,都是可以嘗試的方向。

DAST For Comply With DevSecOps

這個題目之前也有寫過一篇文章介紹,主要是團隊希望可以遵從 DevSecOps 的精神。DevSecOps 是一種觀念或者說是一種實踐方法,這個詞是由 Development、Security 和 Operations 三個詞組合而成的。DevSecOps 的目標是在軟體開發生命週期的早期就整合安全性,以實現更安全的產品和流程。

如果我們可以導入 DevSecOps 的精神,在產品生命週期的各個 stage 執行對應的安全性檢測,就可以更快的獲得 feedback,也可以盡量避免有漏洞的應用被部署到 production 環境中。

因為整個產品的開發週期其實會需要不同的角色去協作,所以我們先拉回身為開發者最直接可以影響的 CI/CD Pipeline。

如果盡量貫徹 DevSecOps 的話,理想的前端專案 CI/CD pipeline 應該會是以下這個樣子:

白色為原本既有的流程,紅色則為 Security 相關的步驟

而 Infra Team 研究的 Dynamic Application Security Testing (DAST) 則是選擇在部署到 Staging 環境後去做檢測,使用的是 ZAP 這個開源工具,掃描後可以得出一份 Security Report,團隊成員可以針對報告去處理專案中潛在的資安漏洞。

ZAP Scan Report

那如果是小專案或小團隊,還能導入 Frontend Infra 嗎?

針對這個問題,我們一樣先看看 ChatGPT 會怎麼說:

針對這個問題,它的回答跟我的想法蠻相近的。根據前面段落的說明,不可否認的是大型的組織與團隊對於前端 Infra 的需求一定是比較強烈的,但現在我們再次回顧文章前段提到的 Frontend Infra 的普遍認知:

Frontend Infra 這個詞通常被用來描述為了提升「開發效率」和「產品品質」而導入的一套系統、流程或工具,並且常常包括一些關於如何使用這些工具和系統的最佳實踐或標準。

重點就在於「開發效率」與「產品質量」這兩個要素,我認為只要符合這兩個規範,任何嘗試都可以被算在 Frontend Infra 的範疇裡。

「開發效率」這點很直覺,例如導入 Hot Module Replacement(HMR) 或是打造 Design System 都可以提升開發效率,而關於「產品質量」,我覺得可以再進一步細分為「程式碼品質」與「產品品質」,像是 SonarQube、ESLint 等工具都可以協助我們提升程式碼品質,而像效能優化、應用監控則可以提升產品品質。

當然以小型團隊或是個人開發者來說,自己實作前端專案的基礎建設會需要很大的成本,但其實現在很多現成的服務或工具讓打造自己前端專案的 Infra 變得更加容易。如果你有在關注 Vercel 這間公司(它就是開發 Next.js 這個框架的公司)它在前陣子的 conference 有提出 Frontend Cloud 這個名詞,其實概念就是希望能簡化前端開發者打造基礎建設的難度。

而我前陣子剛好有機會幫朋友的一個小型前端 Side Project 建立基礎建設,這邊快速分享一下我導入了哪些事項。

Enforcing Standard

關於統一 coding standard,選擇的還是最熟為人知的 Prettier + ESLint 並搭配 husky 在 pre-commit 階段觸發,有趣的是透過 lint-staged 我們可以只對 staged(即已經被 git add 的)檔案進行操作,透過客製化 config 可以指定針對不同副檔名的檔案想要進行什麼樣的操作。

Dependency Management

關於專案中的套件管理,我們是使用 Renovate 這個工具,它可以定期自動化的幫我們發 Pull Request 更新 package.json 有用到的 dependencies 與 devDependencies,避免專案中的依賴套件長期沒有更新造成版本落後過多的狀況,未來如果要一次升級會比較麻煩,也容易遇到 breaking change。Renovate 其實不只支援 JavaScript,它還支援了其他程式語言的套件管理,例如 Golang, Java, Python…等等,它也提供非常豐富的 config 可以設定,例如指定每過多久要檢查一次有沒有可以升版的套件並自動發 PR、或是指定只升級 patch 版本或是只升級 patch 跟 minor 而不升級 major 版本…等等都是可以做到的,有興趣的話可以再自行查看官方文件提供的設定。

使用 Renovate 後對於我們的改變是過往我們可能在 package.json 中的套件版本是使用以下的格式:

  • ^x.x.x (當套件有新的 minor, patch 版本將會自動安裝新版本)
  • ~x.x.x (當套件有新的 patch 版本會自動安裝新版本)

但是這樣會讓每次 install 都有可能用到不同版本的套件,不知不覺間就讓應用出現不預期錯誤的經驗不在少數。原本不使用 pin 版本的寫法就是擔心套件的更新頻率會過低,但有了 Renovate 後再搭配完整的 CI workflow,如果自動化升級套件的 PR CI Pipeline是有通過的,我們可以更有信心的認為這次升版不會造成應用壞掉,這使套件管理這件事變得輕鬆不少。

Preview URL

Preview URL 可以在每次發 PR 或是在 PR 中有新的 commit 時都會自動部署一個版本並提供 URL 給進行 code review 的工程師或是 QA 工程師測試,我認為這是一個可以大幅優化開發流程的工具。

之前在 Infra Team 其實也嘗試打造過 Preview URL,但後來發現這個 feature 其實牽涉很多複雜的流程,當時光打造一個 POC 就花了不少功夫。在這個 Side Project,我們選擇使用 Vercel 提供的 Preview URL 功能,除了為每個 PR 部署一個測試版本以外,共同協作者還能在 Preview Site 上留言給予回饋,這無疑讓工程師與設計師、QA 工程師的協作又多加了一層便利性。

而透過 Vercel 的 Preview URL 功能也應證了剛剛提到的 Frontend Cloud 概念,這個平台確實讓導入 Frontend Infra 的流程再簡化不少。

Vercel 的 Preview URL 還有讓協作者一同留言討論的功能

Development Tools

在這個專案中有加入了一些可以協助開發又不會增加 production bundle size 的工具,例如可以觀察不同頁面 bundle size 組成的 bundle analyzer、找出不必要重新渲染的 Why Did You Render、畫出專案 dependencies graph 的 madge…等等,挑選適當的輔助工具可以增加團隊的開發效率與品質。

但如果不顧團隊需求胡亂地添加工具而不考慮其用途或與現有工具的兼容性可能導致開發環境混亂、學習曲線加長,甚至引入不必要的錯誤。過多或冗餘的工具不僅可能增加設置和維護的複雜性,還可能削弱團隊的焦點,導致生產效率下降,因此在導入任何工具以前都建議先三思喔!

CI/CD Pipeline

CI/CD Pipeline 對於 Frontend Infra 有著重要的價值,主要包含「快速迭代」、「品質保證」、「降低風險」、「自動化」…等等優勢,所以在這個 Side Project 中,我花了蠻多時間在思考如何優化 CI/CD Pipeline 的流程與效率。

Docker Image Size 優化

Docker Image 的 Size 會直接影響 Pipeline 的 Build Time 與 Deploy Time,甚至也會影響儲存與網路的資源耗費,所以我們希望盡可能優化 Dockerfile 的結構與減少 build 出來的 image size。

這個專案是一個 Next.js 開發的應用,最初版的 Dockerfile 是最簡單的寫法,但在 local build image 後發現 Image Size 是不可思議的 3.4 GB😰,後來第二版透過 Multi Stage Build 將 Image Size 減少到 871 MB,雖然進步蠻多的,但我總覺得對於一個開始開發不久的專案來說還是有點過於肥大,後來發現 Next.js 有推出 Output Tracing 這個方案,可以更近一步減少 Image Size 到 216 MB (以上 Image Size 都是 local build 後的大小,實際在 CI / CD workflow build 出來的大小通常會再小一些)。我想除了 Next.js 以外,各種 framework 應該都有針對優化 image size 的特殊方式,建議大家可以去研究看看。

GitHub Actions Cache & Artifact

每個 CI Provider 都有自己獨特的功能與限制,建議大家要花點時間了解自己使用服務的相關資訊。

如果你跟我一樣習慣使用 GitHub Actions,一定對 Cache 與 Artifacts 不陌生,這兩者都提供了儲存和取回資料的功能,但它們的使用情境和特性有所不同。

  • Artifacts 更偏向於「結果的儲存與共享」,它保存的是 workflow 產生的重要文件,例如 build 的 bundle size 報告、Lighthoue CI 檢測結果的文件…等等。
Artifact 用來儲存重要文件
  • Cache 更偏向於「加速 workflow」,它保存的是可能在多次工作流之間重複使用的文件或資料,例如 npm install後產生的 node_modules,如果我們發現package.jsonlock file 沒有改動,可以合理推斷並沒有新的套件被安裝或更新,這時候可以重用快取的套件,就不需要再跑一次 install。(關於 GHA 的快取機制可以參考我之前的一篇文章)
指定 cache key,如果 cache hit 就不需要重跑 yarn install

然而 GitHub Actions 針對不同方案的使用者,對於 Cache 與 Artifact 都有對應的使用限制。

以這個 Side Project 來說,它是一個免費方案的 Public Repository,對於 Cache 與 Artifacts 的限制如下:

Cache: 一個 Repo 的 size limit 是 10 GB,如果 7 天都沒有被 hit 到的 Cache 就會被清除。

Artifact:一個 Repo 只能存 2 GB,不管有沒有被使用,在 90 天後都會自動清除。

免費帳號 public repo 的 Cache 與 Artifacts 的限制

了解這些限制其實很重要,因為如果是在公司裡面導入這些都是跟金錢成本有關的事情,如果當前的限額沒辦法滿足團隊的需求,可能就得考慮花費更多金錢來升級方案。

因為 GHA 的 cache 是用分支與 identifier 來作識別的,也就是說,假設今天我有一個 branch,你也有一個 branch,即便我們的 lockfile 內容一樣,因此獲得的 cache key 也一樣,但還是會因為在不同的分支而形成兩個 Cache Item,而我的分支不能使用你的分支的快取,反之亦然。

在這個專案大約會有 15-20 位協作者,在多人高頻率發 PR 的狀況下,Cache 可能很快就會超過 Size Limit ,也因為是用分支作識別,所以很多快取其時在 PR 被 merge 分支被刪除後就不太會用到了,但依照規則還是需要 7 天後才會被清除,很明顯有很多除存空間被浪費了。為了避免太快超過 Cache 的 size limit,我們在思考有沒有方式可以自己刪除用不到的快取。

雖然 GitHub 有提供可以手動刪除 Cache 的管理介面

但身為工程師,可以自動化的事情為什麼要手動做呢?透過 GitHub Actions 與 GitHub API 並指定 PR Close 事件要 trigger 就可以輕鬆做到自動化清除用不到的快取以避免用量超過 Size Limit 囉!

Bundle Size Diffing

雖然已經有導入 Bundle Analyzer 可以觀察 Next.js 應用的 bundle chunks 狀況,但我想多數人不會想到要沒事就去看 bundle 的狀況,等到哪天發現 bundle 變得異常肥大,通常也 trace 不出一切到底是從哪裡開始變了調😂 我們在 CI 中加入 bundle size diff 的流程並顯示在 PR comments 上,可以看到 PR 前後 bundle size 的變動,未來如果出現問題也比較方便 trace。

而加入這步驟其實不需要什麼 effort,因為在 CI 中本來就需要執行 next build,我們只需要把 build 後的純文字資訊存到 artifact 就可以在未來用來進行比對。

Knip

雖然 ESLint 已經可以抓出很多語法錯誤,但它的範疇主要限於單一檔案層級的檢查,它不具備檢查整專案層級的能力。

例如,程式碼中可能有這樣的一行:export const myVar = true;。ESLint 將檔案以單獨的方式處理,所以它不知道 myVar 是否在其他地方被使用。而Knip 正好派上用場,它能夠對整個 codebase 進行檢查,找出未被使用的 export、files 與 dependencies,這可以幫助提升專案的可維護性與性能。

我們選擇把 Knip 這個工具綁到 CI / CD 流程中,在每兩週一次的 release 後去執行檢測,除了復盤這個 Sprint 的程式碼品質,也可以決定下個 Sprint 是否要排進相關的 Refactor。

Development Process Optimization

大部分的 CI Provider 在執行 workflow 時都可以取得 PR 或是 Repository 相關的資訊,例如說 PR title、PR number、label…等等資訊。雖然這些資訊第一眼看起來可能沒什麼用,但它們可能比你想的還有價值。

我的經驗是,有了這些 PR 相關的 meta data,再搭配 GitHub API,我們其實可以做到非常非常多的事,像是上面提過的 Lighthouse CI Diffing、Bundle Size Diffing,因為需要保存每一次檢測的狀況,我們可以選擇用這些 meta data 當作 unique 的 identifier 方便我們管理資源。

再舉一個有趣的例子,我在幫忙建立這個專案的基礎建設時,發現每位協作者對於 PR Title 的寫法都很遵守規範,例如是 feature 就會寫 feat: xxx,是修 bug 就寫 fix: xxx,但對於 label 的使用大家習慣就不太一樣,有些人習慣上好上滿,有些人卻不放上任何的 label。我自己在開發上是蠻習慣放 label 的,因為可以方便未來做 filter 與分類。但當然我覺得上 label 只是一個很 minor 的事情,我不希望針對這麼小的事讓協作者產生負擔。於是我想到既然大家很遵守 PR title 規範,那我應該可以根據 PR title 去自動幫 PR 加上 label 分類,於是我透過在 GitHub Actions 中寫一點 Node.js script 就完成這件事。(後來才發現原來之前就有人想到一樣的事情,而且已經寫成了更完整的 Custom Action 🤣)

提到這個例子主要是想要分享我覺得 CI/CD Pipeline 其實充滿很多可以提升開發體驗或流程的可能性,只要想得到就有機會做得到,這就留給各位發揮想像力去玩玩看啦!

Observability

過往講到 Observability,多數人聯想到的還是 backend 的 system 才有這樣的需求,然而近年來 Frontend Observability 也漸漸受到重視。

在前端可觀察性的範疇中,通常會觀察以下幾個重要的面向:

  1. Logging:Logging 是收集應用程序運行時的詳細資訊,比如用戶行為、系統錯誤等。這些 log 可以幫助開發者了解應用的運行狀態和行為。
  2. Tracing:Tracing 是追蹤單一請求的生命週期。例如,追蹤一次 API 請求從發送到接收到響應的全過程,這有助於定位性能瓶頸和錯誤。
  3. Metrics:Metrics 是以統計數據的形式來度量應用程序的性能和健康狀態,如頁面載入時間、錯誤率等。
  4. Web Vitals:LCP、FIP、CLS 等對前端應用來說非常重要的使用者體驗指標。
  5. Error:監控前端應用的各種錯誤、錯誤發生的時間、裝置…等等。

以往不同種類的數據搜集往往需要分散在不同的平台上,例如 Web Vitals 透過 Lighthouse、Error 透過 Sentry,這對於應用的監控來說其實非常不方便。現今很多平台都推出了 Full Stack 的 Observability 解決方案,讓跨越前後端的各種資訊都可以在同一個平台被觀測。

在這個 Side Project 中,團隊目前還在探索不同平台的優缺點,因此還沒有確定最終要導入哪個平台,目前的 Candidate 有 New RelicGrafana Faro、Sentry,有興趣的讀者都可以自行去探索看看喔!

看起來很零碎雜亂…

雖然看起來在這個專案導入的東西似乎非常的零碎,但如果我們把開發流程轉化成流程圖的話

透過流程圖,我們可以很清楚的理解在專案中不同的開發階段會觸發哪些流程,團隊也可以更方便的討論在每一步流程中,是否有多餘或缺少的流程可以去修正。因此我蠻推薦大家可以針對前端應用的開發流程畫出一份基本的流程圖喔!

針對 FE Infra,還能導入什麼?

任何東西。你想得到的技術或工具都有機會。

但是除了要盡量符合剛剛提到的提升「開發效率」或是「產品品質」以外,還有更重要的一件事

如果架構設計脫離了實際業務需求,那就是在瞎忙。調整軟體架構必須深入理解需求,參與需求討論,並透徹理解需求背後的業務本質。

Frontend Infra 的本質也是軟體架構設計,因此在導入任何工具、流程之前,不妨先思考一下目前的專案是否有這個需求,畢竟每導入一個事項對於團隊成員來說都是增加認知負擔,並不是看到什麼東西很潮很酷就可以一率導入到專案中。

想法總結

前端開發者的分類與角色多樣性

前端老實說其實是一個很廣泛的領域,即使職稱都是前端工程師,每個人聚焦與鑽研的面相又都不太一樣。以我自己的觀察來說,前端開發者又可以大略分為幾種類型:

  • Product Developer,專注於複雜的前端應用開發,我想大部分的前端開發者都會屬於這類
  • 專精於動畫、互動設計 (Canva、3D)的前端工程師(例如業界有名的版塊設計的產品就有非常多複雜的動畫效果)
  • Tooling Infra Developer:這類型的 FE Devs 職責就比較聚焦在本文探討的 FE Infra,透過打造工具、制定準則來提昇開發體驗與產品品質。

除了前端本身的分類造成需要的技能樹不同以外,隨著近年技術的發展,前端開發者也需要培養許多過往跟前端開發似乎沒那麼相關的技能,例如簡單的 Server Side 開發、CI/CD、Serverless…等等,我們可以看出現今的前端開發者的角色多樣性是在逐步增加的。

Frontend Infra 跟團隊文化相關

處理 Frontend Infra 相關的任務時,要記住並不是只有導入技術、工具並修改開發流程,它是一件跟團隊文化相關的事情。

當我們導入新的工具或流程時,並非只是技術層面的改變,更重要的是,每增加一個工具都會增加團隊成員的認知複雜度,它將直接影響團隊成員的行為模式。因此,建立一個能夠接納並適應變化的團隊文化,讓團隊成員了解導入任何工具、流程背後的意義與要解決的問題是什麼,對於發展 Frontend Infra 至關重要。

FE Infra 跟 DevOps 的關聯

FE Infra 與 DevOps 兩者其實很明顯有相關之處,它們共同目標是提升軟體開發流程的效率與品質。我們可以視 FE Infra 為 DevOps 這個文化與方法論在前端領域的實踐,兩者緊密結合,共同優化開發流程。

理解需求,不需要過度導入

前面提過「如果架構設計脫離了實際業務需求,那就是在瞎忙。」

在前端專案想要導入任何基礎建設時,可以先思考一下是否有這個需求?如果有的話導入這個工具或流程後可以多大限度的解決我們的問題?團隊文化是否適合?成本是否可以承受?

導入任何東西前經過通盤思考與初步驗證,更有機會達到期望的價值。

WebConf 2023

本篇文章也是自己在 WebConf 2023 的議程主題,自己喜歡把演講的主題也寫成文字版本與更多人分享,感謝主辦單位的邀請,是一個超棒的技術社群活動!

第一次在高級會議廳演講