自JavaScript誕生以來,前端技術發展很是迅速。移動端白屏優化是前端界面體驗的一個重要優化方向,Web 前端誕生了 SSR 、CSR、預渲染等技術。css
十年前,幾乎全部網站都使用 ASP、Java、PHP 這類作後端渲染,但後來隨着 jQuery、Angular、React、Vue 等 JS 框架的崛起,開始轉向了前端渲染。2014年起又興起了同構渲染,號稱是將來,集成了先後端渲染的優勢,當真如此?html
咱們先明確三個概念:前端
後端渲染:後端渲染指傳統的 ASP、Java 或 PHP 的渲染機制;vue
CSR:前端渲染 指使用 JS 來渲染頁面大部份內容,表明是如今流行的 SPA 單頁面應用;node
同構渲染:指先後端共用 JS,首次渲染時使用 Node.js 來直出 HTML。通常來講同構渲染是介於先後端中的共有部分webpack
以及經常使用性能測試時間點ios
在前端渲染領域,主要有如下幾種方式可供選擇:git
CSR | 預渲染 | SSR | 同構 | |
---|---|---|---|---|
優勢 |
|
|
|
|
缺點 |
|
|
|
|
由上表格可得知,各類渲染模式優缺點各異,看起來並無那麼完美的解決方案,咱們只能依據自身產品需求,選擇最適合咱們的渲染方案。github
一、一個優秀的產品 ,離不開SEO,它包含了不少方面的知識,通常公司都會配置專門的SEO職位, 畢竟有太多事情要作了。而咱們做爲一個有追(破 )求(不)完(得)美(已)的前端,在開發的時候,須要作好頁面結構科學、標籤語義化、站點路由精簡、提供必要的爬蟲信息(如 Robot.txt,Sitemap,標籤 role,ref 等等);然而在現實中CSR大行其道,SPA站點更是數不勝數,用戶體驗獲得了質的提高,然而,然而,爲了兼顧SEO,開發者不得不爲爬蟲提供專門的shadowsite,或者本身頂起下載本身的頁面提供給爬蟲,或者使用SSR,刀耕火種的年代。。。web
二、首屏渲染速度
目前先後端的分離的前端項目須要先加載靜態資源,再異步獲取數據,最後渲染頁面,在這個過程當中的前兩部頁面都是沒有數據的,影響了首屏的渲染速度,也就影響了用戶的體驗。 目前對於首屏渲染速度的提高有許多方案,在ssr以外還有龍骨,墓碑,數據直出。相比於這些方案ssr方案實現是最複雜的,但效果也是最好的。
三、方案選擇
vue 中作同構,有兩種,一種是基於官方Vue SSR指南推薦的SSR,一種是vueJS通用應用框架 NUXT.
官網方案,能夠更直接的控制應用程序,更深刻底層,也比較靈活。NUXT,你懂得,就是那種你拿來即用的效果,提供了部分額外功能,e.g. 靜態站點,可用於快速實現Vue SSR
SSR和預渲染的使用場景仍是有比較明顯的區別的,預渲染的使用場景更多的是咱們所說的靜態頁面的形式。而SSR適用於大型的。頁面數據處理較多且較爲複雜、與服務端有數據交互的功能性網站,一個明顯的使用場景就是電商網站
今天爲你們介紹的這個,是部分同構方案,開始。。。
從官網借來的圖可知,SSR有兩個入口文件,entry-client和entry-server兩個文件,都包含了應用代碼,webpack會根據這兩個入口文件分別打包成給服務端用的,Server Bundle及客戶端使用的Client Bundle ,當服務器接收到了來自客戶端的請求以後,會建立一個渲染器 bundleRenderer,這個 bundleRenderer 會讀取上面生成的 server bundle 文件,而且執行它的代碼, 而後發送一個生成好的 html 到瀏覽器,等到客戶端加載了 client bundle 以後,會和服務端生成的DOM 進行 Hydration (判斷這個 DOM 和本身即將生成的 DOM 是否相同,若是相同就將客戶端的Vue實例掛載到這個 DOM 上, 不然會提示警告)。
而在vue服務器端渲染時,就不能只是使用web-dev-server和web-hot-middle了,由於咱們須要添加服務器渲染的node代碼邏輯,這樣,咱們能夠本身開一個node服務器,使用webpack-dev-middle中間件進行打包、使用webpack-hot-middle中間件進行熱更新,並添加服務器端渲染邏輯,即node端經過引入vue-serverer-renderer插件來渲染服務器端打包的bundle文件到客戶端。
因此在項目開發期間,其實咱們是運行着兩個node服務,一個作代理服務,一個提供ssr和其餘的一些服務。
一、client-server的做用:
二、entry-server的做用:
createBundleRenderer
,這裏會檢查組件是否有 asyncData 方法,而後下一步
二、因爲在node環境中,沒法用webpack進行CSS文件處理,因此在配置文件中咱們須要對服務端渲染時,進行CSS白名單處理
1 externals: TARGET_NODE? nodeExternals({whitelist: [/\.css$/] }):undefined
三、咱們從打包出來的代碼中能夠看到,是vue-ssr-server-bundle.json,而很是規的JS文件。這是由於node環境下,每次打包成js文件,你得考慮node的熱部署,而且node環境也不支持sourcemap,因此引入了 vue-server-renderer 組件,這種方式相似於常規的render,支持熱部署,支持source map ,在配置文件中,咱們配置了該組件下的服務端渲染插件,可使得服務端渲染輸出的是json文件。
四、
在CSR模式下,咱們開發過程當中會進行熱部署,這樣會大大提升工做效率。
1 let bundle 2 serverCompiler.watch({}, (err, stats) => { 3 if (err) { 4 throw err 5 } 6 stats = stats.toJson() 7 stats.errors.forEach(error => console.error(error)) 8 stats.warnings.forEach(warn => console.warn(warn)) 9 const bundlePath = path.join( 10 webpackConfig.output.path, 11 'vue-ssr-server-bundle.json' 12 ) 13 bundle = JSON.parse(mfs.readFileSync(bundlePath, 'utf-8')) 14 console.log('new bundle generated') 15 })
一、服務器預獲取數據的異常處理,參考上面的entry-server中所說,讓客戶端主動獲取數據,再次嘗試渲染
二、在服務端數據預獲取的生命週期結束後的渲染頁面過程當中出現的異常,包括各類操做數據的語法錯誤等,如對undefined取屬性。編寫過程要注意全局環境下的代碼,是否試用,作環境判斷。
雖然 Vue 的服務器端渲染(SSR)至關快速,可是因爲建立組件實例和虛擬 DOM 節點的開銷,沒法與純基於字符串拼接(pure string-based)的模板的性能至關。在 SSR 性能相當重要的狀況下,明智地利用緩存策略,能夠極大改善響應時間並減小服務器負載,這是一個取捨的過程。vue服務區緩存分爲頁面緩存、組建緩存和接口緩存;
將渲染完成的頁面緩存到內存中,同時設置最大緩存數量和緩存時間。 優點:大幅度提升頁面的訪問速度 代價:增長服務器內存的使用
1 const microCache = LRU({ 2 max: 100, // 最大緩存的數目 3 maxAge: 1000 // 重要提示:條目在 1 秒後過時。 4 }) 5 const isCacheable = req => { 6 // 判斷是否須要頁面緩存 7 if (req.url && req.url === '/') { 8 return req.url 9 } else { 10 return false 11 } 12 } 13 const handleRequest = async (ctx, next) => { 14 const req = ctx.req 15 const res = ctx.res 16 const cacheable = isCacheable(req) 17 if (cacheable) { 18 const hit = microCache.get(res.url) 19 if (hit) { 20 return res.end(hit) 21 } 22 } 23 ... 24 ... 25 }
使用較少,本次並未涉及
將通用的接口緩存到內存,減小服務端接口請求的時間
get (url, params = {}) { // url = baseUrl + '/sa' + url url = baseUrl + url const key = md5(url + JSON.stringify(params)) // 判斷是否有緩存,直接返回緩存結果 if (params.cache && microCache.get(key)) { return Promise.resolve(microCache.get(key)) } let Cookie = '' if (params.req && params.req.headers && params.req.headers.cookie) { Cookie = params.req.headers.cookie } return new Promise((resolve, reject) => { axios({ url, params, headers: { 'X-Requested-With': 'XMLHttpRequest', 'Cookie': Cookie }, method: 'get' }).then(res => { // 判斷是否須要緩存 若是須要緩存緩存數據 if (params.cache && microCache) { microCache.set(key, res.data) } resolve(res.data) }).catch(error => { reject(error) }) }) },
咱們是否真正的須要作同構渲染,這取決因素有不少,主要有,SEO,首屏時間比較重要的產品可考慮。
運用該技術並無想象中的輕鬆,對前端開發有必定的要求,編寫過程要謹慎,涉及構建設置和部署的更多要求,還須要更多的服務器端負載,總之,咱們可能須要的支持會更多一點。
Demo已上傳至github,以供參考,如若對您有幫助,給個小星星仍是很開心的,傳送門