為什么要寫本文呢,話說現(xiàn)在vue-ssr 官網(wǎng)上對(duì) vue 服務(wù)端渲染的介紹已經(jīng)很全面了,包括各種服務(wù)端渲染框架比如 Nuxt.js 、 集成 Koa 和vue-server-renderer 的 node.js 框架 egg.js,都有自己的官網(wǎng)和團(tuán)隊(duì)在維護(hù),文檔真是面面俱到功能強(qiáng)大,但是,我個(gè)人在剛開始看這些資料的時(shí)候,總是忍不住發(fā)起靈魂三問:“我是誰?我在哪?我在干什么?”,提前沒有相關(guān)知識(shí)的人開始學(xué)這些,肯定是要走一些彎路或者卡在某個(gè)點(diǎn)一段時(shí)間的,所以我想把我的學(xué)習(xí)經(jīng)驗(yàn)做下總結(jié),一方面方便自己以后查閱,一方面也會(huì)在文中加一些針對(duì)官網(wǎng)上沒有細(xì)說的點(diǎn)的理解,希望能幫助你減少些學(xué)習(xí)成本,畢竟這是一個(gè)知識(shí)共享的時(shí)代嘛。本文不涉及到源碼解析,主要講解如何實(shí)現(xiàn) vue 的服務(wù)端渲染,比較適合 vue-ssr 小白閱讀,下面我們進(jìn)入正文:
創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、會(huì)昌網(wǎng)絡(luò)推廣、重慶小程序開發(fā)、會(huì)昌網(wǎng)絡(luò)營(yíng)銷、會(huì)昌企業(yè)策劃、會(huì)昌品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供會(huì)昌建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com
先說下基本概念:
ssr 的全稱是 server side render,服務(wù)端渲染,vue ssr 的意思就是在服務(wù)端進(jìn)行 vue 的渲染,直接對(duì)前端返回帶有數(shù)據(jù),并且是渲染好的HTML頁面;而不是返回一個(gè)空的HTML頁面,再由vue 通過異步請(qǐng)求來獲取數(shù)據(jù),再重新補(bǔ)充到頁面中。
這么做的最主要原因,就是搜索引擎優(yōu)化,也就是SEO,這更利于網(wǎng)絡(luò)爬蟲去爬取和收集數(shù)據(jù)。
為什么這樣就有利于網(wǎng)絡(luò)爬蟲爬取呢?
這里簡(jiǎn)單說一下爬蟲的爬取方式,爬蟲通過訪問 URL 獲取一個(gè)頁面后,會(huì)獲取當(dāng)前HTML中已存在的數(shù)據(jù),也可以理解為把拿到的 HTML 頁面轉(zhuǎn)為了字符串內(nèi)容,然后解析、存儲(chǔ)這些內(nèi)容,但是如果頁面中有些數(shù)據(jù)是通過異步請(qǐng)求獲得的,那么爬蟲是不會(huì)等待異步請(qǐng)求返回之后才結(jié)束對(duì)頁面數(shù)據(jù)的解析的,這樣就會(huì)沒有爬取到這部分?jǐn)?shù)據(jù),很不利于其他搜索引擎的收錄。
這也就是為什么單頁面網(wǎng)站是不具備良好的SEO效果的,因?yàn)閱雾撁娣祷氐木褪且粋€(gè)基本為空的 HTML 文件,里面就一個(gè)帶有ID的元素等待掛載而已,頁面的內(nèi)容都是通過 js 后續(xù)生成的,比如這樣:
Hello
但對(duì)于很多公司來說,公司的產(chǎn)品是希望能被百度、谷歌等搜索引擎收錄之后,進(jìn)行排名,進(jìn)一步的被用戶搜索到,能更利于品牌的推廣、流量變現(xiàn)等操作,要實(shí)現(xiàn)這些,就必須保證產(chǎn)品的網(wǎng)頁是能夠被網(wǎng)絡(luò)爬蟲爬取到的,顯然一個(gè)完整的帶有全部數(shù)據(jù)的頁面更利于爬蟲的爬取,當(dāng)然現(xiàn)在也有很多方法可以去實(shí)現(xiàn)針對(duì)頁面異步數(shù)據(jù)的爬取,github 上也開源了很多的爬蟲代碼,但是這顯然對(duì)于爬蟲來說更加的不友好、成本更高。
SSR 當(dāng)然也是有著其他的好處的,比如首屏頁面加載速度更快,用戶等待時(shí)間更短等,其他更多概念可以查看官網(wǎng) https://ssr.vuejs.org/zh/ ,這些官網(wǎng)上都有介紹。
代碼實(shí)現(xiàn)
下面我們結(jié)合官網(wǎng)上的代碼,做一下代碼實(shí)操,來加深下理解:
在官網(wǎng)中,提供了一個(gè)使用模塊 vue-server-renderer 簡(jiǎn)單實(shí)現(xiàn) vue 服務(wù)端渲染的示例:
新建一個(gè)文件夾vue-ssr-demo,進(jìn)入其中執(zhí)行如下命令:
// 安裝模塊 npm install vue vue-server-renderer --save
創(chuàng)建文件 server.js
// vue-ssr-demo/server.js 示例代碼 //第一步,創(chuàng)建vue實(shí)例 const Vue = require('vue'); const app = new Vue({ template: "hello world" }); //第二步,創(chuàng)建一個(gè)renderer const renderer = require('vue-server-renderer').createRenderer(); //第三步,將vue渲染為HTML renderer.renderToString(app, (err, html)=>{ if(err){ throw err; } console.log(html); });
保存以上代碼后,在 vue-ssr-demo 文件夾下打開命令行工具,執(zhí)行 node server.js 命令,可得到如下 HTML 內(nèi)容:
➜ vue-ssr-demo node server.jshello world
好,上面的例子中我們已經(jīng)讓 vue 在服務(wù)端,也就是 node 環(huán)境下運(yùn)行起來了,到這里其實(shí)已經(jīng)實(shí)現(xiàn)了 vue 的服務(wù)端渲染了。
可是,實(shí)際項(xiàng)目中使用哪有這么簡(jiǎn)單,起碼數(shù)據(jù)還沒渲染啊,那接下來我們看看如何渲染數(shù)據(jù):
vue-ssr 渲染數(shù)據(jù)的方式有兩種,我們先看下第一種:
// server.js const data_vue = { word: 'Hello World!' }; //第一步,創(chuàng)建vue實(shí)例 const Vue = require('vue'); //vue 實(shí)例化過程中插入數(shù)據(jù) const app = new Vue({ data: data_vue, template: "{{word}}" }); //第二步,創(chuàng)建一個(gè)renderer const renderer = require('vue-server-renderer').createRenderer(); //第三步,將vue渲染為HTML renderer.renderToString(app, (err, html)=>{ if(err){ throw err; } console.log(html); });
第一種方式,在創(chuàng)建 vue 實(shí)例時(shí),將需要的數(shù)據(jù)傳入 vue 的模板,使用方法與客戶端 vue 一樣;運(yùn)行 server.js 結(jié)果如下,數(shù)據(jù) data_vue 已經(jīng)插入到 vue 模板里面了:
➜ vue-ssr-demo node server.jsHello World!
第二種,模板插值,這里我們也直接先放代碼:
const data_vue = { word: 'Hello World!' }; const data_tpl = { people: 'Hello People!' }; //第一步,創(chuàng)建vue實(shí)例 const Vue = require('vue'); const app = new Vue({ data: data_vue, template: "{{word}}" }); //第二步,創(chuàng)建一個(gè) renderer 實(shí)例 const renderer = require('vue-server-renderer').createRenderer({ template: "{{people}}" }); //第三步,將vue渲染為HTML renderer.renderToString(app, data_tpl, (err, html)=>{ if(err){ throw err; } console.log(html); });
這里我們?cè)黾恿藬?shù)據(jù) data_tpl,你會(huì)發(fā)現(xiàn),在 renderToString 方法中傳入了這個(gè)參數(shù),那么這個(gè)參數(shù)作用在哪里呢?這就要看下官網(wǎng)中關(guān)于 createRenderer 和 renderToString 方法的介紹了,
createRenderer: 使用(可選的)選項(xiàng)創(chuàng)建一個(gè) Renderer 實(shí)例。 const { createRenderer } = require('vue-server-renderer') const renderer = createRenderer({ / 選項(xiàng) / })
在選項(xiàng)中,就有一個(gè)參數(shù)叫 template,看官網(wǎng)怎么說的:
template: 為整個(gè)頁面的 HTML 提供一個(gè)模板。此模板應(yīng)包含注釋 ,作為渲染應(yīng)用程序內(nèi)容的占位符。
為整個(gè)頁面的 HTML 提供一個(gè)模板。此模板應(yīng)包含注釋 ,作為渲染應(yīng)用程序內(nèi)容的占位符。
模板還支持使用渲染上下文 (render context) 進(jìn)行基本插值:
使用雙花括號(hào) (double-mustache) 進(jìn)行 HTML 轉(zhuǎn)義插值 (HTML-escaped interpolation);
使用三花括號(hào) (triple-mustache) 進(jìn)行 HTML 不轉(zhuǎn)義插值 (non-HTML-escaped interpolation)。
根據(jù)介紹,在創(chuàng)建 renderer 實(shí)例時(shí),可以通過 template 參數(shù)聲明一個(gè)模板,這個(gè)模板用來干嘛呢?就用來掛載 vue 模板渲染完成之后生成的 HTML。這里要注意一下,當(dāng)創(chuàng)建 renderer 實(shí)例時(shí)沒有聲明 template 參數(shù),那么默認(rèn)渲染完就是 vue 模板生成的 HTML;當(dāng)創(chuàng)建 renderer 實(shí)例時(shí)聲明了 template 參數(shù),一定要在模板中增加一句注釋 “” 作為 vue 模板插入的占位符,否則會(huì)報(bào)找不到插入模板位置的錯(cuò)誤。
再次運(yùn)行 server.js ,結(jié)果如下,vue 模板已成功插入,且 template 模板中的 {{people}} 變量也因在 renderToString 方法中第二位參數(shù)的傳入,顯示了數(shù)據(jù):
vue-ssr-demo node server.jsHello World!Hello People!
如果我們把 template 換成一個(gè) HTML 頁面的基本架構(gòu),來包裹 vue 模板,是不是就能得到一個(gè)完整頁面了呢?我們來試一下:
const data_vue = { word: 'Hello World!' }; const data_tpl = { people: 'Hello People!' }; //第一步,創(chuàng)建vue實(shí)例 const Vue = require('vue'); const app = new Vue({ data: data_vue, template: "{{word}}" }); //第二步,創(chuàng)建一個(gè)renderer const renderer = require('vue-server-renderer').createRenderer({ template: `Hello {{people}}` }); //第三步,將vue渲染為HTML renderer.renderToString(app, data_tpl, (err, html)=>{ if(err){ throw err; } console.log(html); });
運(yùn)行 server.js ,結(jié)果如下,我們得到了一個(gè)完整的 HTML 頁面,且成功插入了數(shù)據(jù):
vue-ssr-demo node server.jsHello Hello World!Hello People!
好,現(xiàn)在頁面生成了,該怎么顯示呢?這里我們借助下框架 Koa 實(shí)現(xiàn),先來安裝:
npm install koa -S
然后修改 server.js ,如下:
const data_vue = { word: 'Hello World!' }; const data_tpl = { people: 'Hello People!' }; const Koa = require('koa'); //創(chuàng)建 koa 實(shí)例 const koa = new Koa(); const Vue = require('vue'); //創(chuàng)建一個(gè)renderer const renderer = require('vue-server-renderer').createRenderer({ template: `Hello {{people}}` }); // 對(duì)于任何請(qǐng)求,app將調(diào)用該異步函數(shù)處理請(qǐng)求: koa.use(async (ctx, next) => { // await next(); //創(chuàng)建vue實(shí)例 const app = new Vue({ data: data_vue, template: "{{word}}" }); //將vue渲染為HTML const body = await renderer.renderToString(app, data_tpl); ctx.body = body; }); // 在端口3001監(jiān)聽: koa.listen(3001); console.log('app started at port 3001...');
運(yùn)行 server.js :
vue-ssr-demo node server.js app started at port 3001...
然后打開瀏覽器,輸入網(wǎng)址 http://localhost:3001/ ,即可看到運(yùn)行后的效果。
這樣就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的服務(wù)端渲染項(xiàng)目,但是我們?cè)谄匠i_發(fā)的時(shí)候,肯定不會(huì)這么簡(jiǎn)單的去構(gòu)建一個(gè)項(xiàng)目,必然會(huì)用到一些,比如打包、壓縮的工具,這篇就寫到這里,下一篇我們嘗試使用 webpack 來構(gòu)建一個(gè) vue 的服務(wù)端渲染項(xiàng)目。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。