主要介紹一下怎麼由vue-cli應用經過修改,變成能用于服務端和用戶端的通用同構代碼。希望能給到新接觸SSR的的同學一些指導~
1、為啥要用伺服器端渲染?
與傳統 SPA(Single-Page Application - 單頁應用程式)相比,伺服器端渲染(SSR)的優勢主要在于:
更好的 SEO,由于搜尋引擎爬蟲抓取工具可以直接檢視完全渲染的頁面。
更快的内容到達時間(time-to-content),特别是對于緩慢的網絡情況或運作緩慢的裝置。無需等待所有的 JavaScript 都完成下載下傳并執行,才顯示伺服器渲染的标記,是以你的使用者将會更快速地看到完整渲染的頁面。通常可以産生更好的使用者體驗,并且對于那些「内容到達時間(time-to-content)與轉化率直接相關」的應用程式而言,伺服器端渲染(SSR)至關重要。
2、沒有什麼隻有好處沒有壞處,,SSR也是,,,
1、開發複雜化。你需要更加注意同一份代碼在伺服器端和客戶單端兩種環境的執行,,你需要仔細消息各種生命周期的鈎子函數,,還有一些可能伺服器渲染的結果和用戶端渲染不一緻導緻的報錯等。
2、建構和部署複雜化。你需要配置和打包服務端代碼,用戶端代碼。而且,如果你還想繼續使用cdn版,你還要配置和打包非ssr版代碼。部署也涉及node部署,server代碼部署,cdn代碼部署。
3、增加node渲染服務端負載。相對于cdn版本,ssr版增加了ssr node server,大流量時,明顯需要更多的人力和技術去支撐node server這部分的工作。
平常應用中,一般需要ssr的就是首屏直出,給使用者比較快的頁面達到時間。其他地方對ssr需求并不是很大,,相對于ssr帶來的弊端,合理權衡是很重要的事。
3、使用SSR時,輸入網址 到 看到頁面 是 什麼個流程 ?
以開發代碼為例。
▲ 服務端準備階段(setup-dev-server.js)
1、讀 index.html 模闆檔案,使用webpack.client.config.js打包用戶端代碼(額外生成了client-manifest.json清單檔案),監控代碼變化。
2、使用webpack.server.config.js打包服務端代碼(生成server-bundle.json檔案),把server-bundle檔案以及上面的client-manifest.json清單檔案傳回給伺服器server.js。監控代碼變化并重新打包。 這兩步凡是有代碼變化,都重新打包服務端和用戶端代碼。
3、有bundle和manifest檔案了,調用 ssr 核心庫函數,renderer = createBundleRenderer(...)
4、服務端準備就緒。

▲ 服務端渲染階段(entry-server.js)
1、一個請求過來了
2、定義一個渲染上下文 context,(可以給其指派自定義資料),renderer(context, callback(result_html)),renderer會将context環境,傳入并調用entry-server.js 暴露出來的函數。渲染完成後生成 html 傳給回調,然後 res.send(html) 給用戶端。結束。
3、再看下裡面的渲染過程。entry-server.js 先 createApp()建立一個執行個體。再擷取頁面url,比對router,更新路由狀态:router.push(url)。等路由準備好後,加載目前路由對應component暴露出來的預加載資料鈎子函數。待所有加載資料完成後,儲存狀态:context.state = store.state,,,這個很重要,renderer會保這個狀态插入到window.__INITIAL_STATE_這個變量裡。這邊變量将使用者用戶端恢複伺服器資料狀态。路由、資料都準備好後,開始renderer自身的dom渲染了。 用戶端manifest檔案會被利用,把相關的js,css檔案等插入到渲染後的html字元串裡面。
▲ 用戶端處理(entry-client.js)
1、用戶端收到了 server res.send(html)的源碼了。
2、浏覽器加載完基礎檔案後,開始執行 entry-client.js 裡的過程。先 createApp() 建立一個執行個體,解析伺服器插入的狀态window.__INITIAL_STATE_資料,替換目前store狀态 store.replaceState(window.__INITIAL_STATE__),然後 挂載到 dom上,app.$mount('#app')。期間,用戶端可以做一些 data prefetch工作,如:router.beforeResolve,Vue.beforeRouteUpdate 等等。