airbnb 的 Hypernova 跟已有的 Universal JS 解決方案相比有哪些優勢?
airbnb 的 Hypernova(https://github.com/airbnb/hypernova)開源了。這種方案看上去比較簡單,並且 airbnb 也用在了 production 環境中,它究竟有何優點?
知道這問題為什麼這麼久沒人回答嗎?因為
- 一個前端應用要用到伺服器端渲染的時候,場景已經非常窄了,如果應用沒有滿足下面兩個條件,用來幹嘛
- 前端有非常非常非常多的view要處理
- 這些view的改動非常非常頻繁
- 99%的應用是這情況嗎?遠遠不是,我好好的前端統一起來渲染,在架構上顯然一致性和可維護性更好,若伺服器端渲染,優化破壞分層架構的一致性,本來好好的,前端干前端的事,後端處理數據邏輯當API用,乾乾淨淨
- 另一個原因,是真要用伺服器端渲染的時候,我幹嘛非得UniversalJS,我就是用ExpressJS這樣的框架,也大可以開一個EndPoint把HTML傳回來,這樣靈活性還大些,因為本身ExpressJS這樣的框架本身就和業務數據很近,意味著要變換伺服器端渲染結果就容易得多,這在PHP3時代就存在了,PHP直接輸出HTML,沒什麼不好
- 至於hypernovaJS,這是UniversalJS的一種實現,給了點工具讓UniversalJS看上去沒那麼糟糕,但改變不了UniversalJS只是一種邊際場景的事實
- 普通應用,真的別費這個勁
只好拋磚引玉了。
在我看來,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
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 |