服務器端渲染 Server-Side Rendering 也常被人寫做 SSR 是 Vue.js 2.0 版本發佈的時候同時推出的功能,Virtual-DOM 的實現讓 DOM 生成被 JavaScript 來描述也就給了先後端在 JavaScript 環境下均可以生成頁面內容,而其最主要的業務 vue-server-renderer也包含在了 Vue.js核心庫中。前端
1.SEO:除了 Google 和 Bing 比較完美地實現了對於 SPA(Single-Page Application)的爬蟲渲染及內容抓取,大多數搜索引擎包括百度都沒有支持。於是,包含豐富內容的產品並須要 SEO 流量的產品也就天然須要 SSR 實現。vue
2.加載速度:Faster Time-to-Contentnode
當網站是 SPA 時,渲染網站須要:第一次加載 HTML、加載 JavaScript、加載相應頁面須要的 Vue Components(爲了性能大多數組建都是異步取的)、渲染 DOM、加載數據、渲染 DOM、展現 … 然後端提早渲染好頁面,能夠快速展現到頁面內容(其實加載數據部分的時間成本是省不下來的),於是還包含了使用緩存、renderToStream 等等優化速度的方法。webpack
在使用服務端渲染的時候,首先要有個server端。由於在開發vue項目時,須要起一個webpack-dev-server的服務,端口8000。由於咱們要使用它的熱更替,這樣能加快開發效率。web
因爲webpack是一個自主的server,咱們沒有辦法在裏面添加服務端渲染的代碼,而這段代碼是須要本身去寫的,因此須要再起一個node server,去執行服務端渲染的邏輯。json
咱們會用到vue-server-renderer這個包來幫咱們在node.js環境裏面去渲染出vue代碼生成的HTML代碼,這部分代碼是直接返回給用戶的,用戶能夠在瀏覽器裏直接看到HTML的內容。後端
以圖爲例,咱們看到兩個渲染的過程,兩種server。若是直接訪問webpack-dev-server,就跟咱們以前開發的過程同樣,它是一個純前端渲染的過程。若是咱們要走服務端渲染的流程,就要走node server服務,端口3333以示區別。數組
並且須要打包一個邏輯到node端運行,經過webpack-server-compiler去生成一個server bundle,也就是服務端的app.js。當node server 獲取到server bundle以後,就能夠執行vue-server-renderer,去渲染出HTML的代碼,直接返回給用戶,這樣的話就不須要經過js再去渲染出頁面內容,減小了用戶的等待時間。瀏覽器
如何編寫服務器端渲染的配置文件?緩存
首先咱們須要在項目根目錄裏面找到build文件夾,而後在其下面新建一個webpack.config.server.js文件,具體配置代碼,我先擼爲敬:
const path = require('path')
剛接觸SSR的童鞋,不要暈,我來帶你們一一分析下。
target: 'node',
target須要指定爲node,由於打包出來的程序是在node端運行的,不是在瀏覽器端運行,因此要指定打包的目標是node環境。
entry: path.join(__dirname, '../client/server-entry.js'),
entry須要提供一個單獨的入口文件,因此須要在client文件夾下新建一個server-entry.js文件。
devtool: 'source-map',
devtool須要指定source-map,由於vue-server-renderer有個webpack插件,它能提供代碼調試的功能,不過只能提示到出錯的文件出在哪一行。
libraryTarget: 'commonjs2',
指定libraryTarget的類型爲commonjs2,用來指定代碼export出去的入口的形式。在node.js中模塊是module.exports = {...},commonjs2打包出來的代碼出口形式就相似於此。
externals: Object.keys(require('../package.json').dependencies),
externals是外部因素的意思,首先咱們能夠打開package.json文件看看dependencies
咱們用Object.keys()獲得的就是一個數組。externals就是告訴webpack不要去打包node_modules裏面的js代碼。
devDependencies裏面是一些工具型的東西,在應用真正跑起來的時候是不須要的。只有在執行一些打包,工具化操做的時候纔會須要它。
'process.env.VUE_ENV': '"server"'
這是vue服務端官方建議咱們這麼去作的,在vue-server-renderer裏面可能會用到這個屬性。
const VueServerPlugin = require('vue-server-renderer/server-plugin')
這個插件能幫咱們單獨地生成一個json文件,用於在vue的服務端渲染裏面能幫助咱們處理一些很複雜的邏輯。
服務器端渲染和客戶端渲染有何區別?
首先咱們將經過下面這份簡單的時間線圖展現SSR與CSR(即客戶端渲染)之間的區別。
能夠看到其中最大的區別在於,在使用SSR的狀況下服務器對瀏覽器的響應結果屬於已作好準備並可進行渲染的頁面HTML,而CSR的瀏覽器響應結果則屬於連接至JavaScript的空文檔。這意味着瀏覽器將立足服務器進行HTML渲染,而無需等待所有JavaSciprt代碼的下載與執行。
在這兩種狀況下,咱們都須要下載React並利用一樣的流程構建一個虛擬dom,然後附加各事件以實現頁面交互——但在SSR方面,用戶可在執行上述流程的同時查看到頁面內容。而在CSR方面,你們則須要等待上述流程所有執行完成,然後方可進行查看。
注意事項
1.儘管在SSR方面,頁面會提早進行渲染以幫助客戶更早查看頁面內容,但在React真正執行完成以後,查看到的內容並沒有法進行交互。若是客戶在此期間點擊某按鈕,該操做亦須要等待React執行完成後方可起效;
2.SSR TTFB(即第一字節時間)速度比CSR更慢,由於服務器須要耗費時間爲頁面建立HTML,而非直接發送相對較空的響應內容;
3.SSR的服務器數據吞吐量要遠低於CSR數據通量。以React爲例,這種數據吞吐量的差別將形成顯著區別。
ReactDOMServer.renderToString爲一項同步CPU綁定調用,其中包含該事件循環,意味着服務器將沒法在
4.ReactDOMServer.renderToString完成以前處理其它請求。這裏咱們假定頁面須要500毫秒進行SSR,則意味着每秒至多隻能執行2項請求。
實際案例
在下圖當中,咱們就walmart.com網站上的各生產應用對SSR與CSR進行渲染效果比對。
咱們將三款應用(即主頁、分類與搜索)分別立足SSR與CSR方式進行比較。相關結果來自Chrome瀏覽器所捕捉到的頁面渲染時間指標。
你們可能已經注意到,SSR渲染速度要更快一些,而使用CSR則意味着加載過程當中瀏覽器內將顯示空白頁面。大多數使用CSR的應用都會利用加載圖標來取代這種難看的空白頁面,但因爲咱們在正常操做中默認使用SSR,所以在CSR測試中頁面仍保持未經發動的空白樣式。
須要注意的是,上述結果皆爲咱們的設備在一天中特定時段內配合實際生產配置捕捉到的結果,所以通過定製化調整的方案也許在性能上有所區別——不過整體而言,其仍然足以反映通常性趨勢。
上圖爲主頁、分類與搜索頁面的首次服務器響應對比。在這裏忽略掉了綠色指標條,由於其更多反映的是網絡圖中的其它元素。這裏最值得關注的實際上是文檔大小與TTFB。
因爲服務器會利用HTML對頁面進行響應,所以你們能夠看到SSR的文檔老是相對較大。另外須要強調的是,正如前文中所提到,CSR響應速度更快(除了主頁,這是由於受到本次測試中某些因素的影響)。
上述測量指標會隨着應用類型、延遲、服務器、位置以及多種其它變量的變化而有所浮動,所以請不要將其視爲科學的客觀事實——而僅用於反映一種廣泛規律。
Electrode框架
在咱們對SSR與CSR進行A/B測試時,得出了以上整體趨勢,而咱們的數字也顯示儘早進行渲染每每可以帶來更理想的操做體驗。
考慮到這些理由,開源應用平臺Electrode高度關注SSR。其默認啓用SSR,而咱們亦構建起多種模塊以進一步提高SSR性能表現。