多多少少有些不開心的事, 以爲精力沒有被投入在重點上
創業公司遇到問題變成盲人摸象也許正常吧
不過最近這段時間由於服務端的策略調整, 我開始作一些服務端渲染
主要的站點是簡聊的登陸頁面, 總體從 Jade 切換到了 React
https://account.jianliao.com/signin
以及作了一些總體項目結構統一的工做, 或者說一些思考html
我估計這些問題已經被考慮過不少次, 特別是對於發展較快的那些公司
由於富交互的應用和較大的網站的需求, 很容易導向這個結果
而爲了保證交互效果以及產量, 提出相應的方案是天然的一個結果
Teambition 主站的同窗以前有講過 ejs 共用代碼的方案
我大體記得是後端渲染, 前端編譯, 還從新實現了路由, 大體的
簡聊(https://jianliao.com)這裏的嘗試晚了半年一年, 層次也不深, 用 React 難度也低一些前端
這些天 Coding 在好多地方刷了幾篇服務端渲染的廣告, 學習目的推薦看下
http://segmentfault.com/a/1190000004120539
http://segmentfault.com/a/1190000004094442node
簡聊沒有繼續跟進 Redux 和 JSX 的方案, 實際上細節處理很不同
總體的思路固然差不太多, Yahoo 的 fluxible 當時演示的方案已經成熟
我整理一下大致思路吧, 也許用獲得, 特別是中間一些坑
大體有這麼幾點, 在開發以前就須要考慮清楚的react
先後端共用的渲染模塊webpack
先後端共用的數據層實現git
先後端共用的路由方案github
先後端共用的類庫web
簡聊技術棧當中已有的模塊, 可以在服務端共用的:ajax
渲染模塊: React 內置功能, 輕鬆實現數據庫
數據層實現: actions-recorder 是很簡單的封裝
路由方案: router-view 功能少, 容易自由組合
共用類庫: 經過 typeof window 強制判斷控制加載
先後端渲染, 實際上整體的思路仍是前端單頁面渲染的套路
單頁面, 會先建立好 Model, 而後根據 Model 和 Router 渲染 View
渲染在 React 當中就簡化成爲初次渲染, 以及後續數據和操做的更新
而服務端渲染, 僅僅是把初次渲染放在服務端進行, 後邊照常
所以, 雖然說是共用代碼, 但實際上只是支持單頁面在服務端作初次渲染
共用渲染代碼原本是最難的, 然而 React 出現之後幾乎不是個事情
只是渲染的性能讓 React 的實用性打了折扣
不過 0.14 以後有新的模塊在嘗試, 號稱性能提高明顯
總體思路就是把渲染過程轉化爲 Node 經常使用的 Stream
https://github.com/aickin/react-dom-stream
我沒有實際用, 不過這個方案須要手動封裝 HTML 的 <head>
部分
方案的代碼是 fork 了 react-dom 官方實現作的, 看起來挺長
我仍是等等事件提供更好的方案吧
數據層須要作的主要是定義一個渲染頁面所需的 initialStore
這個 initialStore 能夠用於服務端的初次渲染, 也能夠用於客戶端
簡聊網頁版用的 actions-recorder 在服務端渲染時幾乎每作什麼
整個 initialStore 直接被輸出爲 JSON 寫在 HTML head 當中
<script>window._initialStore= (JSON.stringify(store))</script>
前端代碼初始化時讀取其中的數據, 從新用 actions-recorder 初始化一遍
通常服務端寫 initialStore 以前會作一些操做
好比說服務端能拿到的 cookie 或者其餘的一些配置
或者是後面要說的路由信息, 由於簡聊的路由是等效 JSON 表示的
服務端是代替客戶端作了一些初始化工做, 不然前端初始化也是相似的代碼
router-view 包含兩部分代碼, 一部分是解析路由, 另外一部分是渲染和監聽
固然, 初次以外, 還有接口能夠定義路由規則, 我挺懶
若是有興趣看看內部實現和實例也就算了, 很短的代碼
https://github.com/teambition/router-view
頁面初次渲染的過程, 大體就是解析出路由, 渲染對應頁面就完了
路由解析在後端作, 在前端作, 只是獲取 path 的 API 不一樣而已
這裏卻是有一點要注意, 服務端渲染有特別的地方, 就是初次操做
好比說, 打開一個頁面, 會自動觸發一個操做, 好比驗證某些數據
單純按照單頁面的思路, 渲染時不該有操做, 那麼, 操做應該是更早發出
也就是在以前用戶發有操做, 到服務器渲染頁面, 這中間
這種問題在前端作, 總架構考慮, 就該是認爲是用戶打開瀏覽器的行爲上發出
總之儘可能避免認爲是 didMount 的時候發出這樣一個行爲了
路由另一點是隔離 JavaScript/CSS 代碼的做用
固然, 其實仍是經過單頁面應用的套路來實現的, 甚至 Webpack 打包也是
就是說經過 Component 的分割, 將 JavaScript/CSS 限制在每一個頁面裏
咱們早期一些代碼用的是原始的 DOM 操做, 就不容易管理
好比說打包到一塊兒, 萬一 CSS 或者 JavaScript 不該該卻觸發了怎麼辦?
咱們沒有積累強大的後端渲染靜態資源管理方案, 於是這點須要避免...
最主要的問題就是第三方類庫可能影響在 Node 中加載代碼
其實初次渲染極可能用不到不少代碼, 只要加載不報錯就行了
用的辦法簡單粗暴, 就是強制判斷, 而後控制 require 的執行
typeof window isnt undefined
我記得這個仍是之前 AirBnB 放出的幻燈片裏看到用的
實際遇到會是很瑣碎的狀況, 甚至致使代碼都有些難看
可是誰讓 JavaScript 設計時看不到這麼遠的適應場景呢
另外有個辦法, 是用 Webpack 的打包方式, 自動把 Node 模塊過濾掉
這個辦法我是剛學會, 具體看網上的例子:
https://webpack.github.io/docs/configuration.html#node
http://stackoverflow.com/a/34033159/883571
大體說來就是定義一些模塊, 告訴 Webpack 用什麼方案處理
能夠 mock, 能夠引用... 細節我還不清楚, 但值得挖掘
我實踐中遇到最坑的一件事, 莫過於代碼當中存在 event loop
簡聊有段代碼打包後幾萬行, 中間有時間循環, 根本不知道在哪
後來猜測是 setInterval 有問題, 就重置了變量經過報錯定位出來
這種 IO 代碼畢竟不如 pure function 好控制, 能隔離儘可能隔離
先後端渲染主要的好處, 就是作了單頁面, 又保證首屏渲染體驗
若是僅僅是服務端渲染加 jQuery, 組件化會很頭疼
特別是實現比較複雜的功能, 還要遷就初次渲染額外處理, 真的不輕鬆
然而用了 React 不少工做就這麼省掉了
簡聊目前的場景, 就是第一次加載是服務端渲染, 而後前端加載
以後點擊切換路由, 就徹底是 HTML5 路由切換, 徹底是單頁面套路
說簡單除了頁面少, 另外一點是由於數據層幾乎沒有內容
就是說, 從服務端在 HTML head 寫 JSON 傳導前端初始化, 幾乎沒有數據
僅僅是讀取的一些配置信息而已, 因此不涉及數據庫操做
複雜的狀況, 從目前對簡聊主站應用的狀況作的設想
應用在初始化時, 會先裝備好查詢到首屏須要的全部數據
數據拼裝完成, 而後才能開始渲染, 固然到這一步就很簡單了
難度在於怎麼查詢好須要的數據? 並且, 是一套代碼, 不是先後端各一套
那麼要求有更好的抽象機制能作數據查詢的事情, 有點難度
一方面是 polyfill 兩邊的 ajax API, 另外一方面是數據邏輯抽象
我感受跟着 React 和 GraphQL 的思路, 已經觸及一些重要問題了數據和界面之間, 怎麼作好隔離, 然而又怎樣設計界面對數據的依賴?界面自身的組合如何抽象, 數據自身的組合又如何抽象?未來要梳理的問題仍是會有不少