細說 Vue 元件的伺服器端渲染
現在,前後端分離與客戶端渲染已經成為前端開發的主流模式,絕大部分的前端應用都適合用這種方式來開發,又特別是react、vue等元件技術的發展,更是使這種方式深入人心。
但有一些應用,客戶端渲染就會遇到一些問題了:
- 需要做seo(搜尋引擎優化),但客戶端渲染的html中幾乎沒有可用的資訊
- 需要首屏快速載入,但客戶端渲染一般是長時間的載入動畫或者白屏
如果能把客戶端渲染的元件化技術(react、Vue 等)與傳統的後端渲染的方式有效的結合起來,兩者兼具,那就太完美了。
所以,這次就來聊聊 Vue 元件的伺服器端渲染。
根據社群現有的一些方案,結合自己的實踐,針對團隊技術力量的不同,說說不同應用場景選擇方案時的優先順序。
1. Nodejs渲染中間層
一般前後端的工作流是後端 -> 前端。
傳統的後端渲染模式是後端負責包括 url、介面、模板渲染等,前端與後端耦合在一起,當然這種方式正在慢慢的退出歷史舞臺。
主流的客戶端渲染則是後端只提供介面(如有需要,可以提供必要的 url),前端與後端只通過介面交流資料,路由與渲染都在前端完成。
而 NodeJs 渲染中間層的工作流則是後端 -> NodeJs -> 前端(NodeJs 渲染中間層由前端開發人員掌握)。
這種模式下,後端只提供介面,傳統的伺服器端路由(url)、模板渲染則都有 NodeJs 層接管。這樣,前端開發人員可以自由的決定哪些元件需要在伺服器端渲染,哪些元件可以放在客戶端渲染,前後端完全解耦,但又保留了伺服器端渲染的功能。
這種方案最成熟的是nuxt.js。
如果有需要,大家可以自己去nuxt.js 官方文件看看具體的使用方法和詳細的功能。
應該說,這種方式是目前最完美的一種方案,但也有一些隱患:
- 增加了一個 NodeJs 中間層,應用效能會有所降低
- 增加了架構的複雜度、不穩定性,也降低了應用的安全性
- 對於高併發應用,NodeJs 層會很容易形成瓶頸
- 對開發人員要求高了很多
所以,這種方式適合對併發量、安全性、穩定性等要求不高,但又需要做seo或首屏快速載入的頁面。
當然,如果你能夠自己改造相關的工具,就另當別論了。
2. 保留後端模板渲染
當不能使用 NodeJs 中間層時,而又要達到 SEO 與首屏快速響應的目的時,在傳統的後端模板渲染的基礎上,就需要對前端的頁面加以適當的改造。
2.1 首屏快速響應
首屏快速響應就意味著首屏渲染所需的資料是跟html檔案一起到達瀏覽器的,這些資料當前是由後端模板引擎嵌入到 HTML 頁面中的。
以 Java 的freemarker模板引擎為例:
(html中以script的方式獲取模板的資料,這樣就算是在本地除錯、開發,也不會報錯)。
<script>
window.globalData = {
stringValue: '${stringValueTplName}',
intValue: parseInt('${intValueTplName}', 10),
};
</script>
如果是複雜的 Json 資料或者其他複雜的模板資料(比如列表資料),則可以像下面這樣接收:
<script type="text/tpl" id="tpl-script-json">
window.tmpData = {
jsonValue: ${jsonValueTplName},
};
</script>
<script>
try {
eval(document.getElementById('tpl-script-json').innerText);
} catch (e) {
window.tmpData = { jsonValue: {} };
}
window.globalData = {
jsonValue: window.tmpData.jsonValue,
};
</script>
這樣,你就可以在元件裡使用window.globalData的資料了,而不用另外用介面獲取資料,達到加快首屏渲染的目的,而且本地開發、除錯也不會報錯。
如果你使用了本地資料 Mock 功能,也可以很容易的與這種方式結合在一起,只要稍加改造:
- 在程式碼中定義本地和伺服器兩個環境,本地環境使用 Mock 資料,伺服器環境使用window.globalData
- 可以使用see-ajax,see-fetch來簡化這種方式的開發
此外,還有一些措施來進一步加快首屏渲染:
- 儘量減少首屏載入的指令碼檔案大小,其他指令碼可以按需載入
- 如果需要,可以將css、JS 內容注入到 HTML 中,這樣就只會發起一個請求,也可以加快載入速度
2.2 SEO 優化
在上面載入首屏渲染的基礎上,對於 SEO 優化也可以做相應的改造。
其實,在客戶端渲染已慢慢成為主流開發模式的同時,搜尋引擎也在跟進這種變化。
截至目前,Google 和 Bing 可以很好對同步JavaScript應用程式進行索引,也就是說,即使是客戶端渲染,但只要是同步資料渲染(非 Ajax 獲取資料,比如模板資料),搜尋引擎也能抓取到相應的 HTML 片段。
(國內的百度搜索與360搜尋等暫時還沒有跟進動態)
但為了相容所有的搜尋引擎,可以像下面改造:
- 先由後端模板引擎渲染一些 HTML 片段,僅給搜尋引擎抓取,不作為給使用者展示的頁面
- 然後再由客戶端渲染同步或非同步的資料給使用者展示真正的頁面
<div>
<!-- 這裡放置由後端模板引擎渲染的專給搜尋引擎抓取的片段,使用者不可見 -->
</div>
<script>
// 接收同步資料
window.globalData = {
stringValue: '${stringValueTplName}',
intValue: parseInt('${intValueTplName}', 10),
};
</script>
資源搜尋網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com
3. 匯出靜態 html
如果頁面沒有動態資料,那就好辦了,直接把元件匯出為靜態 html,然後由客戶端啟用。
具體過程可以參考官方文件。
這種方案比較好的是nuxt.jsgenerate靜態 HTML 檔案。
目錄結構:
- pages/ # 頁面結構目錄
- index.vue
- second.vue
- ...
- nuxt.config.js # 配置檔案
- package.json
- dist # 匯出靜態 HTML 檔案的預設目錄
匯出靜態 HTML 檔案
npxnuxt generate
如果一個專案裡有多個pages,可以這樣構建:
目錄結構:
- nuxt.config.js # 配置檔案
- package.json
- src/
- home/ # home 頁面
- pages/ # 頁面結構目錄
- index.vue
- second.vue
- ...
- dist # 匯出靜態 HTML 檔案的預設目錄
- about/ # about 頁面
- pages/ # 頁面結構目錄
- index.vue
- second.vue
- ...
- dist # 匯出靜態 HTML 檔案的預設目錄
匯出靜態 HTML 檔案
npx nuxt generate src/home -c ../../nuxt.config.js # home 頁面
npx nuxt generate src/about -c ../../nuxt.config.js # about 頁面
除了上面提到的這些方式外,當然還有其他的方式,比如:
- 使用 Chrome Headless 模式獲取元件的靜態 HTML,參考react-snap,puppeteer
- 官方vue-server-renderer匯出靜態 HTML
4. 總結
因為模式的改變,伺服器端渲染與傳統的後端模板渲染工作方式有很大的不同,所以在開發時需要與後端開發人員做好溝通,避免認知上的不同導致協作不協調。