摘要:很多同學(xué)肯定都想過服務(wù)端渲染的問題。然而一看關(guān)于服務(wù)端渲染的文檔,可能就被唬住了。啪啪啪,啪啪啪好,然后就好了,不到行的代碼,我們就實(shí)現(xiàn)了一個(gè)通用化的服務(wù)化的單頁應(yīng)用服務(wù)端渲染解決方案。
前端發(fā)展到現(xiàn)在,SPA應(yīng)該已經(jīng)被應(yīng)用的非常廣了??上У氖?,我們前進(jìn)的是快,而人家搜索引擎爬蟲跟用戶的瀏覽器設(shè)備還跟不上腳步。辛辛苦苦寫好的單頁應(yīng)用,結(jié)果到了SEO跟瀏覽器兼容這一步懵逼了。
很多同學(xué)肯定都想過服務(wù)端渲染的問題。然而一看vue、react關(guān)于服務(wù)端渲染的文檔,可能就被唬住了。之前寫好的并不能無縫遷移。而且,每當(dāng)有個(gè)項(xiàng)目,就需要去run一套node服務(wù)。當(dāng)然,架構(gòu)能力好些的朋友,可以做好集中化管理。
所以,當(dāng)我想在項(xiàng)目中,采用vue或者react的時(shí)候,就遇到這些非常大的阻力。正當(dāng)我頭疼腦熱的時(shí)候呢,我發(fā)現(xiàn)了一條新途徑。
在前不久呢,同事在群里分享了puppeteer,它GitHub的介紹如下:
Puppeteer is a Node library which provides a high-level API to control headless Chrome over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome.
大意就是說,一個(gè)提供操作Headless Chrome的API的node庫。
再具體的說,就是能在node環(huán)境中,通過一些API,來“模擬”真實(shí)chrome訪問頁面,并對其進(jìn)行模擬用戶操作、獲取DOM等。
那既然它能夠像真實(shí)Chrome那樣去訪問頁面并且輸出渲染后的html,我為什么不能通過它來給我們做服務(wù)端渲染呢?
設(shè)想一下,我們有這樣一個(gè)服務(wù)A,它能夠像chrome一樣訪問指定頁面,并把最終頁面上的dom返回給你。
而你原本的業(yè)務(wù)服務(wù)器B,只需要判斷是爬蟲,或者低版本IE來訪問時(shí),調(diào)取該服務(wù),得到html,將html返回給用戶,這就實(shí)現(xiàn)了服務(wù)端渲染。大致流程圖如下:
有這樣一個(gè)思路后,我們就想辦法來實(shí)踐它。實(shí)踐的過程,就是解決問題的過程。仔細(xì)想想,我們會遇到如下幾個(gè)問題:
Q1: 即使是模擬Chrome去請求頁面,很多時(shí)候視圖也是異步渲染的。比如先請求列表接口,得到數(shù)據(jù)再渲染出列表DOM。這個(gè)時(shí)間,我們并沒有辦法把控。那這個(gè)服務(wù),到底時(shí)候才應(yīng)該把加載完成的HTML返回呢?
遇到問題時(shí),首先可以看看人家的文檔 Puppeteer API。欣喜的是,我們找到了如下幾個(gè)方法:
page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]]) page.waitForFunction(pageFunction[, options[, ...args]]) page.waitForNavigation(options) page.waitForSelector(selector[, options])
我們可以通過一些設(shè)定,讓頁面在某種情況下才返回。比如我們通過設(shè)定 page.waitForSelector("#app"), 讓頁面出現(xiàn) id="app" 的元素時(shí),才把html內(nèi)容返回。
或者通過設(shè)定 page.waitForFunction("window.innerWidth < 100"),當(dāng)頁面寬度小于100px時(shí),才將此時(shí)的html內(nèi)容返回。
通過這些方法,我們就能有辦法控制,想要輸給爬蟲的,是什么時(shí)候、什么樣的頁面。
Q2: 如果IE用戶訪問量比較大怎么辦。我們雖然通過這樣的系統(tǒng),讓本渲染不出頁面的部分瀏覽器(IE9以下)能夠渲染出頁面了。但這樣的請求過程相對而言會更耗時(shí),這不是很合理。
那我們只要做一個(gè)緩存系統(tǒng)便好。每次請求,都會去判斷此請求是否存在未過期的緩存HTML,如果存在,則直接返回緩存HTML,否則再去請求頁面,保存緩存。
Q3: 雖然頁面是出來了,IE用戶還是沒辦法做一些JS的交互。
這個(gè)我們沒辦法在服務(wù)層上去解決了,但我們可以在前端上做更友好的交互提示。如果判斷用戶是低版本IE,則出現(xiàn)一個(gè)小Tip,提示用戶下載更好的瀏覽器,獲取更好的體驗(yàn)。
Q4: 單頁應(yīng)用的路由多是用錨點(diǎn)(哈希模式)來做的,而哈希參數(shù),服務(wù)端無法獲取,那就沒辦法請求正確的頁面了。
這個(gè)有辦法解決,可以采用HTML History模式的路由,如vue-router,然后路由鏈接最好以生成a標(biāo)簽+href的模式寫在頁面中,而不是onclick后js跳轉(zhuǎn),這樣爬蟲能最好的爬取整站頁面。
當(dāng)問題都想到辦法解決后,我們就能開始真正coding了。
啪啪啪,啪啪啪 => SSR-SERVICE
好,然后就好了,不到200行的代碼,我們就實(shí)現(xiàn)了一個(gè) 通用化的、服務(wù)化的、單頁應(yīng)用服務(wù)端渲染解決方案。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88828.html
showImg(https://segmentfault.com/img/bVbvOmp?w=1612&h=888); 隨著React Vue前端框架的興起,出現(xiàn)了Vue-router,react-router-dom等前端路由管理庫,利用他們構(gòu)建出來的單頁面應(yīng)用,也是越來越接近原生的體驗(yàn),再也不是以前的點(diǎn)擊標(biāo)簽跳轉(zhuǎn)頁面,刷新整個(gè)頁面了,那么他們的原理是什么呢? 優(yōu)質(zhì)gitHub開源練手項(xiàng)目: ...
showImg(https://segmentfault.com/img/bVbvOmp?w=1612&h=888); 隨著React Vue前端框架的興起,出現(xiàn)了Vue-router,react-router-dom等前端路由管理庫,利用他們構(gòu)建出來的單頁面應(yīng)用,也是越來越接近原生的體驗(yàn),再也不是以前的點(diǎn)擊標(biāo)簽跳轉(zhuǎn)頁面,刷新整個(gè)頁面了,那么他們的原理是什么呢? 優(yōu)質(zhì)gitHub開源練手項(xiàng)目: ...
showImg(https://segmentfault.com/img/bVbvOmp?w=1612&h=888); 隨著React Vue前端框架的興起,出現(xiàn)了Vue-router,react-router-dom等前端路由管理庫,利用他們構(gòu)建出來的單頁面應(yīng)用,也是越來越接近原生的體驗(yàn),再也不是以前的點(diǎn)擊標(biāo)簽跳轉(zhuǎn)頁面,刷新整個(gè)頁面了,那么他們的原理是什么呢? 優(yōu)質(zhì)gitHub開源練手項(xiàng)目: ...
摘要:也就是說,我們需要做一個(gè)非單頁應(yīng)用的工程化項(xiàng)目?,F(xiàn)在這個(gè)項(xiàng)目的靜態(tài)資源是以文件哈希值來控制的。這個(gè)該怎么解決呢感謝,我們可以通過如下的配置來實(shí)現(xiàn)意思就是如果圖片是在中引用的則不加哈希值,在文件中引入的則加上。 最近金拱門比較火,我們先戳開它的官網(wǎng)看看。 看完后,如果你老板要是讓你做這么一個(gè)網(wǎng)站,一定要seo,一定要兼容IE,你會怎么去做呢? 用vue/react吧,單頁應(yīng)用滿足不了se...
閱讀 2485·2023-04-26 02:18
閱讀 1271·2021-10-14 09:43
閱讀 3841·2021-09-26 10:00
閱讀 6986·2021-09-22 15:28
閱讀 2550·2019-08-30 15:54
閱讀 2612·2019-08-30 15:52
閱讀 486·2019-08-29 11:30
閱讀 3475·2019-08-29 11:05