在目前的前端領域,單頁web
應用(SPA)已經有了比較高的佔有率,比較主流的web
框架React
、Angular
、Vue
幾乎已經統治了前端市場。html
單頁應用確實帶來了更好的先後端分離,以及用戶體驗好、快,內容的改變不須要從新加載整個頁面等等的優勢,喜憂參半,SPA
應用首屏加載慢、白屏以及 SEO
等問題也就慢慢顯露出來。前端
問題的來源是SPA
應用採用的是客戶端渲染,DOM
節點要等待JS
文件加載完畢後纔會生成,因此就浮現了以上幾個問題。vue
爲了解決以上問題,目前有兩個比較主流的解決方案:webpack
SSR
)Prerender
)當服務器接收到請求後,它把須要的組件渲染成 HTML 字符串,而後把它返回給客戶端(這裏統指瀏覽器)。以後,客戶端會接手渲染控制權。git
優點:github
SEO
,因爲搜索引擎爬蟲抓取工具能夠直接查看徹底渲染的頁面。time-to-content
),特別是對於緩慢的網絡狀況或運行緩慢的設備。問題:web
目前已經有了比較成熟的服務端渲染應用框架,React有Next.js,Vue有Nuxt.js(文檔十分詳細,社區也挺豐富👍),它們都是由zeit.co 背後的團隊發佈的,固然你也能夠本身構建一套服務端渲染。chrome
無需使用web
服務器實時動態編譯 HTML
,而是使用預渲染方式,在構建時 (build time
) 簡單地生成針對特定路由的靜態HTML
文件。npm
若是項目中使用 webpack
,你可使用 prerender-spa-plugin 輕鬆地添加預渲染,後面將會具體實現。後端
在對你的應用程序使用服務器端渲染 (SSR
) 以前,你應該問的第一個問題是,是否真的須要它。這主要取決於內容到達時間 (time-to-content
) 對應用程序的重要程度。若是並不過重要,這種狀況下去使用服務器端渲染 (SSR
) 將是一個小題大做之舉。
若是假設你須要更好SEO
和內容到達時間 (time-to-content
) ,若是你使用服務器端渲染 (SSR
) 只是用來改善少數頁面,那麼這個時候你可能更須要預渲染,優勢是設置預渲染更簡單,你能夠得到SSR
的幾乎全部優勢,無需更改代碼或添加服務器端就能輕鬆實現的解決方案。
用prerender-spa-plugin能夠給現有項目加入預渲染,咱們就以Vue
爲實例進行預渲染優化。
先用Vue
官方提供的腳手架3.0搭建一個簡單的Vue
項目,步驟就不寫了,具體實現能夠參照官方文檔。
prerender-spa-plugin
依賴yarn add prerender-spa-plugin --dev
複製代碼
由於這個組件須要依賴Puppeteer,它是是 Google Chrome 團隊官方的無界面(Headless)Chrome 工具,它是一個 Node
庫,提供了一個高級的 API 來控制 DevTools協議上的無頭版 Chrome 。也能夠配置爲使用完整(非無頭)的 Chrome。
鑑於 Puppeteer
須要 Chromium
,可是即使你的上網姿式足夠科學,也一樣會遇到安裝失敗的問題,嘗試了不少解決方案,提供一個成功率較高的解決方案。
在你的項目根目錄建立一個.npmrc
的文件,固然你也能夠直接修改你本機的.npmrc
配置。
// .npmrc
puppeteer_download_host = https://npm.taobao.org/mirrors
複製代碼
而後再嘗試安裝。
vue.config.js
// vue.config.js
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
function resolve (dir) {
return path.join(__dirname, dir)
}
module.exports = {
publicPath: './',
configureWebpack: () => {
if (process.env.NODE_ENV === 'production') {
return {
plugins: [
new PrerenderSPAPlugin({
staticDir: resolve('dist'),
routes: ['/', '/about'], // 你須要預渲染的路由
renderer: new Renderer({
inject: {
_m: 'prerender'
},
// 渲染時顯示瀏覽器窗口,調試時有用
headless: true,
// 等待觸發目標時間後,開始預渲染
renderAfterDocumentEvent: 'render-event'
})
})
]
}
}
}
}
複製代碼
更多詳細的配置能夠查看prerender-spa-plugin
官方文檔,根據需求添加。
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
mounted () {
// 觸發renderAfterDocumentEvent
document.dispatchEvent(new Event('render-event'))
}
}).$mount('#app')
複製代碼
yarn run build
複製代碼
沒有使用預渲染打包獲得的dist
文件夾目錄:
使用預渲染後打包獲得的dist
文件夾目錄:
能夠看到多了一個about
目錄,裏面有一個html
文件。咱們查看一下根目錄的html
文件,也就是首頁的html
文件。
沒有使用預渲染獲得根目錄html文件
:
使用預渲染獲得根目錄html文件
:
我把它們都部署到gh-pages
上,咱們來看一下差異。
沒有使用預渲染請求到的Document
:
使用預渲染請求到的Document
:
能夠看到使用預渲染時初始化的HTML
文件已經有了DOM
結構,這樣爬蟲就能夠來抓取到DOM
結構,SEO
優化更好。
錄了兩個GIF
點擊刷新體驗下差異,提早在調試工具鉤上Disable cache
,每次刷新都不會使用緩存,從新向服務器發起請求。沒有使用預渲染:
使用預渲染:
能夠看到使用預渲染以後首屏幾乎沒有白屏。
能夠點擊下面連接親自體驗一下,Demo地址:
這是我使用時感受比較遺憾的地方,並不必定全面。
我的理解,插件的實現原理是在打包完成以後, 利用了 Puppeteer
的爬取頁面的功能,模擬瀏覽器訪問路由,而後把JS
生成的DOM
結構以HTML
靜態文件的形式再保存下來。
確實是漸進式的解決了SPA
應用潛在的一些問題,而且比較容易的就能集成到現有的項目,但也有遺憾的地方。
本文只是作了一個簡單的Demo
,更多的使用技巧還須要你親手去探索。
文中若是有問題和遺漏,歡迎在評論區指出,若是本文能給幫助到你,請給個點贊
👍和關注
。
也能夠點擊我另外的文章:
本文到此結束,886🚀🚀