展望 Javascript 2016年的趨勢和生態發展

發表於2016-04-19

本文翻譯自State of the Art JavaScript in 2016,加上了部分譯者的觀點。就像是隧道終點前的光明,JS生態的最佳實踐不再劇烈變更著,現在關於需要學什麼越來越明確了。本文就關於核心類庫,狀態管理,語言特性,構建工具,CSS預處理,API & HTTP 類庫,測試工具,依賴管理等等前端開發的方方面面進行了展望和梳理,為你挑出這些最佳實踐和麵向未來的設計~

那麼,你要開始一個嶄新的Javascript前端專案了,或者被之前老專案折騰半死,你也許並沒有和改變進化步伐極快的社群生態保持技術實踐的同步,或者你開始了,但是有大量的可選項不知道怎麼選。React,Flux,Angular,Aurelia,Mocha,Jasmine,Jasmine,Babel,TypeScript,Flow。哦我的天吶這麼多~ 為了讓事件變得更簡單,我們很多人正陷入一個陷阱:被我喜歡的XKCD漫畫描述的很好:

是的,好訊息是現在JS生態開始慢下來了,好專案開始冒出。最佳實踐愛你慢慢變得更清晰了。工程師開始在現有專案上構建自己的工程還是重新創造輪子。

作為起點,下面是我對現代化Web應用各個部分的個人選擇。一些選擇看起來會有些爭議,我會在每個選擇後附上我的基本推理判斷。要注意的是,這些選擇通常是我建立在我目前對社群的觀察和我個人的經歷。你的看法當然會有不同~

核心類庫:React

目前勝者很顯然就是React(譯者:你確定?!)

  • 從頂到底都是元件,你的應用程式程式碼非常容易理解
  • 學習曲線非常平緩,要知道羅列它所有關鍵的API都不會超過一頁A4紙張。
  • JSX非常棒,你可以用獲得JavaScript程式語言的能力和工具鏈來描述頁面
  • 使用Flux和Redux這種單向資料流非常直白來表達業務邏輯
  • React的社群生態圈非常不錯,產出了很多高質量的開發工具如Redux(後續會講到)
  • 在React寫的大型專案中,利用Flux管理起資料流/內部狀態非常容易(而不像在雙向資料繫結中, 例如Angular1.x/Knockout中
  • 如果你需要類似於服務端渲染,那麼選React沒錯了

現在不少全能的大型框架如Ember,Angular,它們承諾說幫你處理所有的事。但是在React生態中,儘管需要對元件做一些決定(哈這就是你為什麼要閱讀本文的原因啦),但是這方案更強壯。很多其他框架,譬如Angular2.0正在快速追趕React。

『選擇React不僅是個技術上的選擇,更多是個商業決定!』

  • 額外獎勵:一旦你要著手構建自己的移動應用,你會感謝ReactNative專案的

(很牽強哈,Angular社群的Ionic也是PC Web向移動端遷移的好選擇。各自的2.0版本也相輔相成推進上)

應用生命週期:Redux

PS: 以上不是它最終的logo

現在我們有了我們的檢視和元件層,應用程式還需要管理資料狀態和應用的生命週期。Redux也是毋容置疑的優勝者。

除了React,Facebook展示了名叫Flux的單向資料流的設計模式。Flux最早用來解決和簡化應用的狀態管理,但是隨之而來,很多開發者提出了不少新的問題如如何儲存資料狀態和從哪傳送Ajax請求。

為了解決這些問題,不少基於Flux模式之上的框架誕生了:Fluxible, Reflux, Alt, Flummox, Lux, Nuclear, Fluxxor 還有很多。

不過,這其中的類Flux的優雅實現最終贏得了社群的關注,它就是Redux。

最重要的是,學習Redux小菜一碟。它的作者,Dan Abranmov是一位非常棒的老師(他的教學視訊非常易懂好學)。通過那些視訊你很容易成為Redux的專家。我見見識到一組幾乎沒有任何React開發經驗的工程師通過學習他的視訊,在幾周內就開發好能上線的React專案(程式碼質量也是頂級的)

Redux的生態系統和Redux本身一樣優秀。從神乎其神的開發者工具到令人記憶深刻的reselect,Redux的社群是你最好的後盾。

不過有一點需要注意的是不要輕易的去嘗試抽象Redux的專案模板。那些模板背後都是有意義有原因的。所以你嘗試盲目修改前確保你已經使用過它和理解這樣組織程式碼背後的原因。

語言:ES6配合Babel,先不加型別

不用再用CoffeeScript了(譯者哭了出來,公司13年大規模的使用它,至今後端JS專案80%都是它的身影)。因為它的大部分好的特性在ES6都有了(它是JavaScript的標準語言規範),而且CoffeeScript的工具很弱(如CoffeeLint),它的社群也在快速的衰落。

ES6是語言的標準。它的大部分特性在最新的主流瀏覽器中已經被實現,Babel是個可插拔ES6編譯器。把它配置到使用合適的預設目標(preset target,如es2015瀏覽器,es2015-node5),就可以開動了。

那麼關於型別呢,TypeScript和Flow都給JavaScript提供了加上靜態型別的功能,來配合編輯器提供更好的IDE支援和不需要測試就能捕獲一些bug。不過我還是建議,先等等看,看看社群的進展和動向。

TypeScript做了很多工作讓JavaScript寫起來看起來非常像Java/C#,但它缺乏完善的現代化的型別系統特性如代數資料型別(它對你真正開始實操靜態型別時是很重要的)。它也不像Flow那樣很好的處理 nulls。

更新:TypeScript有union types也能覆蓋很多使用者開發場景。

Flow比起來似乎更強大,能捕獲到更大範圍的bug異常,但是比較難設定。在語言特性上,它比起Babel落後不少,在Windows上的支援也不好。

我要說些有爭議性的話了:型別在前端開發中並沒有我們想的那麼重要(可能需要寫一篇長文來講述了)。所以就先等著型別系統變得更強健,目前先只使用Babel,同時關注下Flow~

格式和風格:ESlint配合Airbnb指南

關於ESLint異議也不大。使用它的React外掛和良好的es6的支援,幾乎非常完美完成lint的工作。JSLint是過時了,ESLint這個軟體可以單獨完成原本需要 JSHint 和 JSCS 聯合起來做的事。

你需要配置他用你的風格約定。我強烈建議你使用 Airbnb的風格指南,大部分可以被 ESLint airbnb config 來嚴格約束實現。如果你們團隊會在程式碼風格上產生分歧和爭超,那麼拿出這份指南來終結所有的不服!它也不是完美的(因為完美的風格不存在),但保持統一一致的程式碼風格是要高度推薦的。

一旦你開始熟悉它,我建議你開啟更多的規則。在編輯撰寫程式碼時候越多的捕獲不規範(配置你的編輯器IDE使用上這個ESLint外掛),就會避免分歧和在決定費神,從而讓你和團隊更加高效!

依賴管理:僅考慮NPM,CommonJS 和ES6模組

這一點很明確 – 就用NPM。所有東西,忘記之前的bower。類似與 Browserify 和 Webpack 的構建工具把npm的強大功能引到了web上。版本處理變得很簡單,你也獲得了node生態的大部分模組提供的功能。不過CSS的相關處理還是不夠完美。

你可能會考慮的一件事:如何在開發伺服器構建應用。不想Ruby社群的Bundler,npm 常使用萬用字元來指定版本號,導致你開始書寫程式碼到最後部署時候版本號很可能已經變化了。使用 shrinkwrap 檔案來鎖定你的依賴(我建議使用 Uber的 shrinkwrap 來獲得更見一致性的輸入)。同時考慮使用利用類似於 Sinopia 來構建自己的私有npm伺服器。

Babel可以把 ES6 模組語法編譯到CommonJS。意味著你可面向未來的語法,和在使用構建工具(如Webpack 2.0)時獲得它支援的一些靜態程式碼分析工具如 tree shaking 的優勢

構建工具:Webpack

不想在你的頁面檔案中加入非常多的外鏈Script引用,那你就需要一個構建工具來打包你的依賴。如果你也需要允許npm包在瀏覽器執行工作的工具,那麼Webpack就是你需要的。

一年前,關於這塊還有不少選擇。根據你的開發環境,你可以利用Rails的sprockets來解決類似問題。RequireJS,Browserify和Webpack都是以JavaScript基礎的工具,現在RollupJS聲稱自己在ES6模組上處理的更好。

在一個個嘗試使用後,我最終還是高度推薦Webpack:

  • 它有自己獨特的寫法,不過即使是最少見的場景也能找到解決的方法
  • 主流的模組格式都支援(如AMD,CommonJS,Globals寫法)
  • 它有處理有問題模組的能力(不是標準的模組寫法
  • 它能處理CSS檔案
  • 它有最完善的cache busting/hashing 系統(如果你需要把你的資源釋出到CDN)
  • 它內建熱載入功能
  • 它能載入幾乎你需要的一切
  • 它一套令人驚歎的優化列表

Webpack目前也是處理大型SPA應用專案的最好方案,利用它的程式碼切割(code splitting)和懶載入特性。

不過它的學習曲線很陡峭,但是一點你掌握了,你還是會認為非常值得因為它的強大功能。

那麼Gulp或Grunt呢? Webpack比起來最適合處理靜態資源。所以他們開始可以用來跑一些其他的任務(但是也不推薦),現在更簡單的方法是直接用上 npm scripts

測試:Mocha + Chai + Sinon(但沒那麼簡單)

目前在 JavaScript 單元測試上,我們有眾多選擇,你選擇任何一個都不會錯太多。因為你開始做單元測試,你就走對一大步了。

一些選擇包括了 Jasmine,Mocha,TapeAVA 和 Jest。我知道我漏掉來一些,它們都有一些比其他做的好的地方。

我對一個測試框架的的選擇標準是:

  • 它應該可以在瀏覽器中執行從而方便除錯
  • 它應該執行的足夠快
  • 它可以很好的處理解決非同步測試
  • 它可以在命令列就能很方便的使用
  • 它應該允許我使用任意斷言庫,而不會約束限制

第一個指標讓AVA脫穎而出(因為它的確做的非常棒)和Jest(自動Mocking並不像它說的那麼好,因為它太慢了)

選擇Jasmine,Mocha或Tape都不會差太多。我傾向於 Chai 斷言因為它擁有很多外掛,Sinon’s mocks to Jasmine’s built in construct。Mocha的非同步測試支援很棒(你不用在寫類似於 done callback之類的)。Chai as Promised 也是很屌。我強烈建議你使用 Dirty Chai 來避免一些讓人頭疼的問題。Webpack的 mocha loader 讓你編碼時自動執行測試。

對於React而言,Airbnb的Enzyme和Teaspoon(不是Rails那個!)是不錯的相關工具選擇。

我非常喜歡Mocha的特性和支援情況。如果你喜歡一些最小主義的,讀讀這篇關於tape的文章

PS:
Facebook在最近的文章中說,它們是如何擴充套件Jest的。可能對大部分人來說過於複雜了,如果你有那些資源,不關心是否在瀏覽器中跑測試,那麼它就很適合你。

另外,很多人認為我對AVA太武斷了。不要誤會我,AVA的確很棒。但我有個標準:全瀏覽器支援。這樣我們可以直接從任何瀏覽器去執行(來測試跨瀏覽器相容性)同時要方便除錯。如果你不介意那些,你可以使用非常棒的iron-node來debugging。

工具庫:Lodash是絕對王者,但留意 Ramda

JavaScript不像Java或.NET上有很多強大的內建工具集。所以你可能需要引入一個。

Lodash,目前來說應該是雜七雜八都有的首選。同時它類似注入懶求值這樣的特性讓它成為效能最高的選擇之一。如果你不想用你就不要把它全部都匯入,同時:lodash能讓你僅僅引入哪些你需要的函式(這點尤其重要考慮到它現在變得越來越大)。隨著4.x版本帶來,它原生支援可選的函式式模式給那些函數語言程式設計的極客們使用。來看看怎麼使用它

如果你真的很喜歡函數語言程式設計,那麼不管怎麼樣,留意下優秀的Ramda。如果你決定用它,你可能還是需要引入一些lodash函式(Ramda目前專注於資料處理和函式式構建),但這樣你能在JavaScript中以非常友好方式獲得函數語言程式設計的強大功能

Http請求:就只用fetch

許多React應用再也不需要jQuery了。除非你需要使用一些遺留的老舊的第三方元件(它依賴於jQuery),因為根本沒必要。同時,意味著你需要一個類似於$.ajax的替代品。

為了保持簡單,僅僅使用fetch,它在Firefox和Chrome中內建支援。對於其他瀏覽器,你可能需要引入polyfill。我推薦使用isomorphic-fetch 來在伺服器端在內覆蓋了基礎元件選擇。

還有一些其他好的類庫選擇如Axios,但目前在fetch之上沒有多餘需求。

為了更多關於為什麼Promise是重要的討論,請看我們部落格非同步程式碼

樣式:考慮CSS模組

這是個我覺得相對發展較慢的領域。Sass就是目前的選擇,使用node-sass是你JavaScript專案的不錯開始、。我仍然覺得離最終最好的方案還是有很多不足。缺乏引用匯入(如僅僅是從檔案匯入變數和mixin,而不用重新定義選擇器和它的樣式規則)和原生的URL重寫(使它在保持線上程式碼足夠精簡就很困難)。node-sass是一個C寫的類庫,所以要對應好你的Node版本。

LESS並不受此影響,不過它缺了很多Sass的特性功能。

PostCSS 看起來更有生命力,它允許你構建自己的CSS前處理器。我推薦你使用它,即使你已經有了你喜歡的前處理器如SASS,它類似於AutoPrefixer使得你不需要要匯入類似於Bourbon這樣的大型依賴。

有一點需要特殊注意的是,CSS Modules。它限制了CSS的層疊部分,使得我們可以定義更加明確的依賴,來避免衝突。你再也不用擔心Class名稱一致導致的覆蓋,也不用特意為了避免它而新增額外的字首。它和React也配合的很好。有個不足:css-loader和css modules一起使用會導致非常緩慢,如果你的樣式數量不少,那麼在它優化之前還是避免使用它吧。

如果要我現在從頭開始一個新專案,那麼我大概會使用PostCSS配合一些我喜歡的預編譯的CSS類庫。

不管你選擇什麼,我還是推薦你看下我這篇文章CSS performance with Webpack,尤其你也在配套使用SASS。

前後同構:確保你真的需要它

Universal或Isometric的JavaScript代表著JavaScript寫的程式碼可以被同時執行在客戶端和伺服器上。這需要用來在伺服器端預先渲染頁面來提升效能或SEO友好。感謝React,之前只有類似於Ebay或Facebook這樣的巨型科技公司才能實施的方案,現在很多小的開發團隊都能做到。不過它並不那麼容易,它顯著的加大了複雜性,限制了你類庫和工具選擇。

如果你在構建B2C的網站,類似於電商網站,那麼你可能必須使用這個方案。但如果你是在做內部網站或者是B2B應用站點,那麼這樣的效能提升和SEO其實並不需要。所以和你的專案經理討論下,看看是否有必要~

API介面:暫時沒有好方案

看起來每個開發者最後都會疑問那麼關於API介面呢?很多人會直接想到RESTful API(因為太流行了),同時SOAP真的成為過去式了。同時現在也有不少其他標準如:HATEOAS, JSON API,HAL,GraphQL

GraphQL 賦予客戶端強大的能力(也是職責),允許它來實施任意的查詢介面。結合Relay,它能為你處理客戶端狀態和快取。在伺服器端實施GraphQL看起來比較困難而且現有的文件大部分是針對Node.js的

網飛(NetFlix)的Falcor 看起來它也能提供那些Relay和GraphQL提供的功能,但是對於伺服器端的實現要求很低。但現在它僅僅是開發者預覽版沒有正式釋出。

所有這些有名的標準規範有他們各種的奇怪之處。一些是過於複雜,一些只能處理讀取沒有覆蓋到更新介面。一些又嚴重和REST走失。許多人選擇構建它們自己的,但是最終也要解決它們設計上帶來的問題。

我不認為現在有什麼方案是個大滿貫(完美的),但是下面是我對API應該有的功能的一些思考:

  • 它應該是可預測的,你的API節點應該是遵循一致性規範的
  • 它可以在一次就能拉取多個資源的資料(如果你的應用啟動需要來回請求十幾個介面來獲得相關的資源資料,應用的效能應該是非常糟糕的
  • 它可以覆蓋除去讀取,也包括更新的能力(很多方案僅僅提供讀取的
  • 它應該容易debug:譬如看看Chrome的開發者工具的network網路tab下就能審視發生了什麼
  • 它應該容易被消費,譬如可以簡單的通過 fetch API 方式或者有相應的客戶端類庫支援如Relay

我沒有找到能覆蓋這些需求的方案。如果有,務必讓我知道。
同事考慮,如果你實施一個標準化的RESTful資源路徑時,使用Swagger來文件化我們的API。

客戶端軟體:Electron

Electron 是Atom這個優秀編輯器的背後基石。你可以用它來構建自己的應用程式。它的核心,就是一個特殊版本的Node可以來開啟Chrome視窗來渲染GUI頁面,並且能夠獲取到作業系統底層的API(不用藉助瀏覽器的安全沙箱等措施)。你可以打包你的應用程式像其他的桌面客戶端軟體那樣分發安裝包,並且輔以自動更新機制。

這就是用來構建橫跨OSX,WIndows和Linux這多個桌面環境的應用軟體的最簡單的方式,利用起上面提到的所有好用的工具。它也有不錯的文件和活躍的社群支援。

你也許也聽過nw.js(之前叫node-webkit)它年事已高,Electron比它更穩健,更容易上手使用。

來使用這個模板專案來開搞自己的Electron,React和熱更新專案吧,你可以看看這些東西是怎麼相互配合工作的~

向誰學習,從哪學起

社群有一些大牛,你可以在Twitter,Weibo,掘金上關注他們。
還有不少好的文章和連結。

Removing user interface complexity, or why React is awesome 就是對了解React背後實現原理和原因的不錯講述。

如果你不需要,就別用它!

JavaScript生態區發展很快,欣欣向榮,在快速前進著。但是就像是隧道終點前的光明,最佳實踐不在劇烈變更著。現在關於需要學什麼越來越明確了。

最重要的是記住要保持簡單,如無必要,勿增實體。

如果你的應用就是兩三個頁面,那你不需要用到 Router。如果就一個頁面,那麼你也不用Redux,只需要用React自己管理狀態就好。你的應用就是簡單的 CRUD 程式,那麼不需要用到 Relay。你在學習 ES6 的語法,那麼先別急著弄 Async/Await 或者裝飾器。你準備開始學習 React 了,你不必要立馬就去了解 Hot Reload 熱更新和伺服器端渲染。如果你剛剛使用上 Webpack,那麼也別急著就來用程式碼切割(code splitting)和多程式碼塊(multiple chunks)。如果你才開始 Redux,那麼也不用匆忙用 Redux-Form 或 Redux-Sagas。

保持簡單,一次學一樣,你就不會像其他人一樣抱怨JavaScript的破碎(Fatigue

我少了什麼嗎?

這就是我對目前JavaScript生態現狀的看法和觀點。如果你覺得我遺漏了那些類別的討論,或者你認為我在一些選型上的決定不正確,你有更好的可以推薦。那麼留言吧~

 

相關文章