airbnb 的 Hypernova 跟已有的 Universal JS 解決方案相比有哪些優勢?

airbnb 的 Hypernova(https://github.com/airbnb/hypernova)開源了。這種方案看上去比較簡單,並且 airbnb 也用在了 production 環境中,它究竟有何優點?


知道這問題為什麼這麼久沒人回答嗎?因為

  1. 一個前端應用要用到伺服器端渲染的時候,場景已經非常窄了,如果應用沒有滿足下面兩個條件,用來幹嘛

    1. 前端有非常非常非常多的view要處理
    2. 這些view的改動非常非常頻繁
  2. 99%的應用是這情況嗎?遠遠不是,我好好的前端統一起來渲染,在架構上顯然一致性和可維護性更好,若伺服器端渲染,優化破壞分層架構的一致性,本來好好的,前端干前端的事,後端處理數據邏輯當API用,乾乾淨淨
  3. 另一個原因,是真要用伺服器端渲染的時候,我幹嘛非得UniversalJS,我就是用ExpressJS這樣的框架,也大可以開一個EndPoint把HTML傳回來,這樣靈活性還大些,因為本身ExpressJS這樣的框架本身就和業務數據很近,意味著要變換伺服器端渲染結果就容易得多,這在PHP3時代就存在了,PHP直接輸出HTML,沒什麼不好
  4. 至於hypernovaJS,這是UniversalJS的一種實現,給了點工具讓UniversalJS看上去沒那麼糟糕,但改變不了UniversalJS只是一種邊際場景的事實
  5. 普通應用,真的別費這個勁


只好拋磚引玉了。

在我看來,Hypernova提出了一個更靈活,侵入型更輕的方案。它是一個UniversalJS服務。

輕量

UniversalJS是讓 js 代碼在 server 端上運行,除了 nodejs 以外,Rails需要安裝 therubyracer 或者使用內建的ExecJS,php需要安裝 v8js,總之一般都需要對JS語言的支持才能跑的起來,有侵入性並且運行效率也不是那麼高,再加上客戶端代碼需要對Universal進行兼容性的處理,這對本來就比較複雜的React工程來說,無疑是雪上加霜——我都能想像出多少前端搞到這裡的時候都想掀桌了。

而且如果服務端沒有執行JS的特性怎麼辦?

使用Hypernova的話,伺服器端不用考慮這些問題,因為只需要把你想進行客戶端渲染的js的register key發給Hypernoba server, Hypernova 會根據配置找到js文件,並在 nodejs 上下文中較自然的執行code,並返回渲染結果給應用端。你的應用伺服器端不需要查找js文件,也不需要執行js代碼。

對於 Rails 項目來說,需要安裝hypernova gem, 然後在相應的Action中添加:

around_filter :hypernova_render_support
# 這裡對於新版本的Rails應該使用around_action

Hypernova會收集當前頁面中需要渲染的所有component, 在 "after" filter中將這些信息批量一次發給Hypernova server, Hypernova server 會根據配置找到js文件,用擴展後的Module模塊讀取js文件,用vm執行代碼,放入緩存,並返回給Rails。Rails 使用渲染後的數據替換掉response.body中相應的部分,返回response:

new_body = Hypernova.replace_tokens_with_result(
response.body,
@hypernova_batch_mapping,
result
)
response.body = new_body

這樣處理的話,應用伺服器端的實現比較輕量級,不像react-rails和react_on_rails項目, 或多或少需要第三方庫的支持(sprocket, webpack...), 有時候可能不得不做噁心的兼容性升級。

靈活

伺服器端並不限定於某一語言。現在支持的有Rails和Node,php版本也在開發中。

客戶端JS框架也不限定於React。只要支持伺服器端渲染,可以很容易的做一個Adapter。

在合理的配置下,Hypernova也可同時支持多個項目。

易於擴展

Hypernova的client和server端都支持plugin,比如可以在開發模式使用development plugin在出錯時讓瀏覽器顯示一個red box。

顯然,Hypernova是更靈活,更有野心的UniversalJS方案。

玩UniversalJS的同學,你們有新玩(刑)具了。

想嘗試一下的話,我這裡有個Rails + Hypernova + webpack的簡單例子項目:

GitHub - miaopeng/rails-hypernova-webpack-sample: Sample project for Hypernova and Webpack on Rails

官方的例子里用的貌似是browserify。

----

下面簡單比較一下 react-rails, react_on_rails 和 hypernova的設置步驟:

Hypernova:

- server端:添加hypernova的gem, 在controller中添加round_filter,在view中使用render_react_component,傳入register key及數據.

- client端:npm i hypernova-react, 在js里使用hypernova-react的renderReact方法包裝component, 設置register key。添加新的webpack server bundle config, 打包server端js

- 配置hypernova.js服務,在getComponent中為每個register key設置對應的打包後的server端js文件路徑

react-rails:

- server端:添加react-rails的gem, 在view中使用react_component, 傳入component變數名稱, 數據及prerender標識

- client端:引用react_ujs.js, 在js中暴露component為全局變數, 需要添加jsx後綴。

react_on_rails:

- server 端:添加react_on_rails, therubyracer 兩個gem, 在assets.rb中添加webpack路徑,添加server-bunle.js到precompile,在view中使用react_component, 傳入component name,數據及prerender標識

- client端:npm i react-on-rails, 在js里使用ReactOnRails.register包裝component(register key 為import object name)。添加新的webpack server bundle config, 打包server端js

----

比較一下代碼大小:

  • Hypernova:

    - Gem: hypernova version 1.0.0 ruby 行數:669

- JS: hypernova-react version 1.0.0 js 行數:187

  • react-rails

- Gem: react-rails version 1.6.2 ruby 行數:784

- JS: react_ujs in react-rails gem js 行數:193

  • react_on_rails

- Gem: react_on_rails version 5.2.0 ruby 行數:2235

- JS: react-on-rails js 行數:940


若若的問一句, airbnb 的 Hypernova是神馬玩意


引用圖片


推薦閱讀:

說說各位轉行做前端的經驗?
flow.js/typescript 這類定義參數類型的意義何在?
facebook immutable.js 意義何在,使用場景?
如果寫一個靜態HTML頁面,直接寫HTML代碼和用JS動態生成代碼,哪種方式要好點?為什麼?
JS 引擎如何實現 for (let i;...) { } 寫法中每次循環綁定不同的循環變數 i?

TAG:前端開發 | JavaScript | Airbnb愛彼迎 | 前端框架 | React |