給2019前端的5個建議

blank

給2019前端的5個建議

2019 農曆新年即將到來,是時候總結一下團隊過去一年的技術沉澱。過去一年我們支撐的數據相關業務突飛猛進,其中兩個核心平台級產品代碼量分別達到30+萬行和80+萬行,TS 模塊數均超過1000個,協同開發人員增加到20+人。由於歷史原因,開發框架同時基於React 和Angular,考慮到產品的複雜性、人員的短缺和技術背景各異,我們嘗試了各種方法打磨工具體係來提升開發效率,以下是節選的5項主要方法。

一、基於Redux 的狀態管理

從2013年React發布至今已近6個年頭,前端框架逐漸形成React/Vue/Angular 三足鼎立之勢。幾年前還在爭論單向綁定和雙向綁定孰優孰劣,現在三大框架已經不約而同選擇單向綁定,雙向綁定淪為單純的語法糖。無論你是否承認,框架間的差異越來越小,加上Ant-Design / Fusion-Design / NG-ZORRO / ElementUI組件庫的成熟,選擇任一你熟悉的框架都能高效完成業務。

那接下來的核心問題是什麼?我們認為是狀態管理。簡單應用使用組件內State 方便快捷,但隨著應用複雜度上升,會發現數據散落在不同的組件,組件通信會變得異常複雜。我們先後嘗試過原生Redux、分形Fractal 的思路、自研類Mobx 框架、Angular Service,最終認為Redux 依舊是複雜應用數據流處理最佳選項之一。

慶幸的是除了React 社區,Vue 社區有類似的Vuex,Angular 社區有NgRx 也提供了幾乎同樣的能力,甚至NgRx 還可以無縫使用redux-devtools 來調試狀態變化。

blank

無論如何優化,始終要遵循Redux 三原則:

  1. Single source of truth(組件Stateless,數據來源於Store)
  2. State is read-only(只能通過觸發action 來改變State)
  3. Changes are made with pure functions(Reducer 是純函數)

這三個問題我們是通過自研iron-redux庫來解決。

最終我們得到如下扁平的狀態樹。雖龐大但有序,你可以快速而明確的訪問任何數據。

blank
Redux 狀態樹

如何減少樣板代碼?
使用原生Redux,一個常見的請求處理如下。非常冗餘,這是Redux 被很多人詬病的原因

constinitialState={loading=true,error=false,data=[]};functiontodoApp(state=initialState,action){switch(action.type){caseDATA_LOADING:return{...state,loading:true,error:false}caseDATA_SUCCESS:return{...state,loading:false,data:action.payload}caseDATA_ERROR:return{...state,loading:false,error:true}default:returnstate}}

使用iron-redux 後:

classInitialState{data=newAsyncTuple(true);}functionreducer(state=newInitialState(),action){switch(action.type){/** 省略其它 action 处理 */default:returnAsyncTuple.handleAll(prefix,state,action);}}

代碼量減少三分之二! !
主要做了這2點:

  1. 引入了預設的AsyncTuple類型,就是{data: [], loading: boolean, error: boolean}這樣的數據結構;
  2. 使用AsyncTuple.handleAll處理LOADING/SUCCESS/ERROR這3種action,handleAll的代碼很簡單,使用if判斷action.type的後綴即可,源碼在這裡

曾經React 和Angular 是兩個很難調和的框架,開發中浪費了我們大量的人力。通過使用輕量級的iron-redux,完全遵循Redux核心原則下,我們內部實現了除組件層以外幾乎所有代碼的複用。開發規範、工具庫達成一致,開發人員能夠無縫切換,框架差異帶來的額外成本降到很低

二、全面擁抱TypeScript

TypeScript目前可謂大紅大紫,根據2018 stateofjs ,超過50%的使用率以及90%的滿意度,甚至連Jest也正在從Flow切換到TS 。如果你還沒有使用,可以考慮切換,絕對能給項目帶來很大提升。過去一年,我們從部分使用TS 變為全面切換到TS,包括我們自己開發的工具庫等。

TS 最大的優勢是它提供了強大的靜態分析能力,結合TSLint 能對代碼做到更加嚴格的檢查約束。傳統的EcmaScript 由於沒有靜態類型,即使有了ESLint 也只能做到很基本的檢查,一些typo 問題可能線上出了Bug 後才被發現。

下圖是一個前端應用常見的4層架構。代碼和工俱全面擁抱TS後,實現了從後端API接口到View組件的全鏈路靜態分析,具有了完善的代碼提示和校驗能力。

blank
前後端協作簡圖

除了上面講的iron-redux,我們引入Pont 實現前端取數,它可以自動把後端API 映射到前端可調用的請求方法。

Pont實現原理:
Pont (法語:橋)是我們研發的前端取數層框架。對接的後端API 使用Java Swagger,Swagger 能提供所有API 的元訊息,包括請求和響應的類型格式。 Pont 解析API 元訊息生成TS 的取數函數,這些取數函數類型完美,並掛載到API 模塊下。最終代碼中取數效果是這樣的:

blank
接口名、參數、返回值自動提示

Pont實現的效果有:

  1. 根據方法名自動匹配url、method,並且對應到prams、response 類型完美,並能自動提示
  2. 後端API 接口變更後,前端相關聯的請求會自動報錯,再也不擔心後端悄悄改接口前端不知曉
  3. 再也不需要前後端接口約定文檔,使用代碼保證前端取數和後端接口定義完全一致

另外iron-redux 能接收到Pont 接口響應數據格式,並推導出整個Redux 狀態樹的靜態類型定義,Store 中的數據完美的類型提示。效果如下:

blank
Redux 狀態樹自動提示

最終TS讓代碼更加健壯,尤其是對於大型項目,編譯通過幾乎就代表運行正常,也給重構增加了很多信心

三、回歸Sass/Less

2015 年我們就開始實踐CSS Modules,包括後來的styled-components 等,到2019 年css-in-js 方案依舊爭論不休,雖然它確實解決了一些CSS 語言天生的問題,但同時增加了不少成本,新手不夠友好、全局樣式覆蓋成本高漲、偽類處理複雜、與AntD等組件庫結合有坑。與此同時Sass/Less社區也在飛速發展,尤其是Stylelint的成熟,可以通過技術約束的手段來避免CSS的Bad Parts。

  1. 全局污染:約定每個樣式文件只能有一個頂級類,如.home-page{ .top-nav {/**/}, .main-content{ /**/ } } 。如果有多個頂級類,可以使用Stylelint rule 檢測並給出警告。
  2. 依賴管理不徹底。借助webpack 的css-loader,已夠用。
  3. JS 和CSS 變量共享。關於JS 和Sass/Less 變量共享,我們摸索出了自己的解法:
// src/styles/variables.js module . exports = { // 主颜色'primary-color' : '#0C4CFF' , // 出错颜色'error-color' : '#F15533' , // 成功颜色'success-color' : '#35B34A' , };

以下為Webpack 配置,注入變量到Scss

// webpack.config.jsconststyleVariables=require('src/styles/variables');// ...{test:/.scss$/,use:['style-loader','css-loader?sourceMap&minimize',{loader:'sass-loader',options:{data:Object.keys(styleVariables).map(key=>`$${key}:${styleVariables[key]};`).join('n'),sourceMap:true,sourceMapContents:true}}]}//...

在scss 文件中,可以自己引用變量

// page.scss .button { background : $ primary-color ; }

四、開發工具覆蓋全鏈路

2019 年,你幾乎不可能再開發出React/Angular/Vue 級別的框架,也沒必要再造Ant-Design/Fusion-Design/Ng-Zorro 這樣的輪子。難道就沒有機會了嗎?

當然有,結合你自身的產品開發流程,依舊有很多機會。下面是常規項目的開發流程圖,任何一個環節只要深挖,都有提升空間。如果你能通過工具減少一個或多個環節,帶來的價值更大。

blank
產品研發流程

單拿其中的『開發』環節展開,就有很多可擴展的場景:

blank
前端開發工具流

一個有代表性的例子是,我們開發了國際化工具kiwi 。它同樣具有TS 的類型完美,非常強大的文案提示,另外還有:

  1. VS Code插件kiwi linter ,自動對中文文案標紅,如果已有翻譯文案能自動完成替換
  2. Shell 命令全量檢查出沒有翻譯的文案,批量提交給翻譯人員
  3. Codemod 腳本自動實現舊的國際化方案向Kiwi 遷移,成本級低

除了以上三點,未來還計劃開發瀏覽器插件來檢查漏翻文案,利用Husky 在git 提交前對漏翻文案自動做機器翻譯等等。

未來如果你只提供一個代碼庫,那它的價值會非常局限。你可以參照上面的圖表,開發相應的擴展來豐富生態。如果你是新手,推薦學習下編譯原理和對應的擴展開發規範。

五、嚴格徹底的Code Review

過去的一年,我們一共進行了1200+ 多次Code Review(CR),很多同事從剛開始不好意思提MR 到後來追著別人Review,CR 成為每個人的習慣。通過CR 讓項目中任何一行代碼都至少被兩人觸達過,減少了絕大多數的低級錯誤,提升了代碼質量,這也是幫助新人成長最快的方式之一。

blank
其中一個項目MR截圖

Code Review的幾個技巧:

  1. No magic
  2. Explicit not implicit
  3. 覆蓋度比深度重要,覆蓋度追求100%
  4. 頻率比儀式感重要,坐公交蹲廁所打開手機都可以Review 別人代碼,不需要專門組織會議
  5. 粒度要盡可能小,一個組件一個方法均可,可以結合Git Flow
  6. 24h 小時內處理,無問題直接merge,有問題一定要留comment,並且提供action
  7. 對於亟待上線來不及Review 的代碼,可以先合併上線,上線後再補充Review
  8. 需要自上而下的推動,具有完善的規範,同時定期總結Review 經驗來豐富開發規範
  9. CR 並不只是為了找錯,看到好的代碼,不要吝嗇你的讚美
  10. 本質是鼓勵開發者間更多的溝通,互相學習,營造技術文化氛圍

總結

以上5點當然不是我們技術的全部。除此之外我們還實踐了移動端開發、可視化圖表/WebGL、Web Worker、GraphQL、性能優化等等,但這些還停留在術的層面,未來到一定程度會拿出來分享。

如果你也準備或正在開發複雜的前端應用,同時團隊人員多樣技術背景各異,可以參考以上5點,使用Redux 實現規范清晰可預測的狀態管理,深耕TypeScript 來提升代碼健壯性和可維護性,借助各種Lint 工具回歸簡單方便的CSS,不斷打磨自己的開發工具來保證開發規範高效,並嚴格徹底實行Code Review 促進人的交流和提升。

Links

  1. Pont: nefe/pont
  2. Kiwi: nefe/kiwi
  3. iron-redux: nefe/iron-redux
  4. The State of JavaScript 2018

我們還在招聘,歡迎郵件簡歷,來信必回。 shaoyin.ssy @ alibaba-inc.com

What do you think?

Written by marketer

想在JavaScript 裡面用Pattern matching?

blank

前端同構渲染的思考與實踐