亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

vue/vue-cli+express手把教你搭建SSR

2019-11-19 11:21:13
字體:
來源:轉載
供稿:網友

最近簡單的研究了一下SSR,對SSR已經有了一個簡單的認知,主要應用于單頁面應用,Nuxt是SSR很不錯的框架。也有過調研,簡單的用了一下,感覺還是很不錯。但是還是想知道若不依賴于框架又應該如果處理SSR,研究一下做個筆記。

什么是SSR

把Vue組件渲染為服務器端的HTML字符串,將他們直接發送到瀏覽器,最后將靜態標記混合為客戶端上完全交互的應用程序。

為什么要使用SSR

  • 更好的SEO,搜索引擎爬蟲爬取工具可以直接查看完全渲染的頁面
  • 更寬的內容達到時間(time-to-content),當權請求頁面的時候,服務端渲染完數據之后,把渲染好的頁面直接發送給瀏覽器,并進行渲染。瀏覽器只需要解析html不需要去解析js。

SSR弊端

  1. 開發條件受限,Vue組件的某些生命周期鉤子函數不能使用
  2. 開發環境基于Node.js
  3. 會造成服務端更多的負載。在Node.js中渲染完整的應用程序,顯然會比僅僅提供靜態文件server更加占用CPU資源,因此如果你在預料在高流量下使用,請準備響應的服務負載,并明智的采用緩存策略。

準備工作

在正式開始之前,在vue官網找到了一張這個圖片,圖中詳細的講述了vue中對ssr的實現思路。如下圖簡單的說一下。

下圖中很重要的一點就是webpack,在項目過程中會用到webpack的配置,從最左邊開始就是我們所寫入的源碼文件,所有的文件都有一個公共的入口文件app.js,然后就進入了server-entry(服務端入口)和client-entry(客戶端入口),兩個入口文件都要經過webpack,當訪問node端的時候,使用的是服務端渲染,在服務端渲染的時候,會生成一個server-Bender,最后通過server-Bundle可以渲染出HTML頁面,若在客戶端訪問的時候則是使用客戶端渲染,通過client-Bundle在以后渲染出HTML頁面。so~通過這個圖可以很清晰的看出來,接下來會用到兩個文件,一個server入口,一個client入口,最后由webpack生成server-Bundle和client-Bundle,最終當去請求頁面的時候,node中的server-Bundle會生成HTML界面通過client-Bundle混合到html頁面中即可。

對于vue中使用ssr做了一些簡單的了解之后,那么就開始我們要做的第一步吧,首先要創建一個項目,創建一個文件夾,名字不重要,但是最好不要使用中文。

mkdir domecd domenpm init

npm init命令用來初始化package.json文件:

{ "name": "dome",  // 項目名稱 "version": "1.0.0",  // 版本號 "description": "",  // 描述 "main": "index.js",  // 入口文件 "scripts": {     // 命令行執行命令 如:npm run test  "test": "echo /"Error: no test specified/" && exit 1" }, "author": "Aaron",   // 作者 "license": "ISC"   // 許可證}

初始化完成之后接下來需要安裝,項目所需要依賴的包,所有依賴項如下:

npm install express --save-devnpm install vue --save-devnpm install vue-server-render --save-devnpm install vue-router --save-dev

如上所有依賴項一一安裝即可,安裝完成之后就可以進行下一步了。前面說過SSR是服務端預渲染,所以當然要創建一個Node服務來支撐。在dome文件夾下面創建一個index.js文件,并使用express創建一個服務。

代碼如下:

const express = require("express");const app = express();app.get('*',(request,respones) => {  respones.end("ok");})app.listen(3000,() => {  console.log("服務已啟動")});

完成上述代碼之后,為了方便我們需要在package.json添加一個命令,方便后續開發啟動項目。

{ "scripts": {  "test": "echo /"Error: no test specified/" && exit 1",  "start": "node index.js" }}

創建好之后,在命令行直接輸入npm start即可,當控制臺顯示服務已啟動則表示該服務已經啟動成功了。接下來需要打開瀏覽器看一下渲染的結果。在瀏覽器地址欄輸入locahost:3000則可以看到ok兩個字。

SSR渲染手動搭建

前面的準備工作已經做好了,千萬不要完了我們的主要目的不是為了渲染文字,主要的目標是為了渲染*.vue文件或html所以。接下來就是做我們想要做的事情了。接下來就是要修改index.js文件,將之前安裝的`vue
和vue-server-render`引入進來。

由于返回的不再是文字,而是html模板,所以我們要對響應頭進行更改,告訴瀏覽器我們渲染的是什么,否則瀏覽器是不知道該如何渲染服務器返回的數據。

在index.js中引入了vue-server-render之后,在使用的時候,我們需要執行一下vue-server-render其中的creteRender方法,這個方法的作用就是會將vue的實例轉換成html的形式。

既然有了vue-server-render的方法,接下來就需要引入主角了vue,引入之后然后接著在下面創建一個vue實例,在web端使用vue的時候需要傳一些參數給Vue然而在服務端也是如此也可以傳遞一些參數給Vue實例,這個實例也就是后續添加的那些*.vue文件。為了防止用戶訪問的時候頁面數據不會互相干擾,暫時需要把實例放到get請求中,每次有訪問的時候就會創建一個新的實例,渲染新的模板。

creteRender方法能夠把vue的實例轉成html字符串傳遞到瀏覽器。那么接下來由應該怎么做?在vueServerRender方法下面有一個renderToString方法,這個方法就可以幫助我們完成這步操作。這個方法接受的第一個參數是vue的實例,第二個參數是一個回調函數,如果不想使用回調函數的話,這個方法也返回了一個Promise對象,當方法執行成功之后,會在then函數里面返回html結構。

改動如下:

const express = require("express");const Vue = require("vue");const vueServerRender = require("vue-server-render").creteRender();const app = express();app.get('*',(request,respones) => {  const vueApp = new Vue({    data:{      message:"Hello,Vue SSR!"    },    template:`<h1>{{message}}</h1>`   });  respones.status(200);  respones.setHeader("Content-Type","text/html;charset-utf-8;");  vueServerRender.renderToString(vueApp).then((html) => {    respones.end(html);  }).catch(error => console.log(error));})app.listen(3000,() => {  console.log("服務已啟動")});

上述操作完成之后,一定要記得保存,然后重啟服務器,繼續訪問一下locahost:3000,就會看到在服務端寫入的HTML結構了。這樣做好像給我們添加了大量的工作,到底與在web端直接使用有什么區別么?

接下來見證奇跡的時刻到了。在網頁中右鍵查看源代碼就會發現與之前的在web端使用的時候完全不同,可以看到渲染的模板了。如果細心的就會發現一件很有意思的事情,在h1標簽上會有一個data-server-rendered=true這樣的屬性,這個可以告訴我們這個頁面是通過服務端渲染來做的。大家可以去其他各大網站看看哦。沒準會有其他的收獲。

上面的案例中,雖然已經實現了服務端預渲染,但是會有一個很大的缺陷,就是我們所渲染的這個網頁并不完整,沒有文檔聲明,head等等等,當然可能會有一個其他的想法,就是使用es6的模板字符串做拼接就好了啊。確實,這樣也是行的通的,但是這個仍是飲鴆止渴不能徹底的解決問題,如果做過傳統MVC開發的話,就應該知道,MVC開發模式全是基于模板的,現在這種與MVC有些相似的地方,同理也是可以使用模板的。在dome文件夾下創建index.html,并創建好HTML模板。

模板現在有了該如何使用?在creteRender函數可以接收一個對象作為配置參數。配置參數中有一項為template,這項配置的就是我們即將使用的Html模板。這個接收的不是一個單純的路徑,我們需要使用fs模塊將html模板讀取出來。

其配置如下:

let path = require("path");const vueServerRender = require("vue-server-render").creteRender({  template:require("fs").readFileSync(path.join(__dirname,"./index.html"),"utf-8")});

現在模板已經有了,在web端進行開發的時候,需要掛在一個el的掛載點,這樣Vue才知道把這些template渲染在哪,服務端渲染也是如此,同樣也需要告訴Vue將template渲染到什么地方。接下來要做的事情就是在index.html中做手腳。來通知creteRender把template添加到什么地方。

更改index.html文件:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body>  <!--vue-ssr-outlet--></body></html>

可以發現,在html的body里面添加了一段注釋,當將vueServerRender編譯好的html傳到模板當中之后這個地方將被替換成服務端預編譯的模板內容,這樣也算是完成一個簡單的服務端預渲染了。雖然寫入的只是簡單的html渲染,沒有數據交互也沒有頁面交互,也算是一個不小的進展了。

使用SSR搭建項目我們繼續延續上個項目繼續向下開發,大家平時在使用vue-cli搭建項目的時候,都是在src文件夾下面進行開發的,為了和vue項目結構保持一致,同樣需要創建一個src文件夾,并在src文件夾創建conponents,router,utils,view,暫定項目結構就這樣,隨著代碼的編寫會逐漸向項目里面添加內容。

└─src|  ├─components|  ├─router|  ├─utils|  ├─view|  └─app.js└─index.js

初始的目錄結構已經搭建好了之后,接下來需要繼續向下進行,首先要做的就是要在router目錄中添加一個index.js文件,用來創建路由信息(在使用路由的時候一定要確保路由已經安裝)。路由在項目中所起到的作用應該是重要的,路由會通過路徑把頁面和組件之間建立聯系,并且一一的對應起來,完成路由的渲染。

接下來在router下面的index.js文件中寫入如下配置:

const vueRouter = require("vue-router");const Vue = require("vue");Vue.use(vueRouter);modul.exports = () => {  return new vueRouter({    mode:"history",    routers:[      {        path:"/",        component:{          template:`<h1>這里是首頁<h1/>`        },        name:"home"      },      {        path:"/about",        component:{          template:`<h1>這里是關于頁<h1/>`        },        name:"about"      }    ]  })}

上面的代碼中,仔細觀察的話,和平時在vue-cli中所導出的方式是不一樣的,這里采用了工廠方法,這里為什么要這樣?記得在雛形里面說過,為了保證用戶每次訪問都要生成一個新的路由,防止用戶與用戶之間相互影響,也就是說Vue實例是新的,我們的vue-router的實例也應該保證它是一個全新的。

現在Vue實例和服務端混在一起,這樣對于項目的維護是很不好的,所以也需要把Vue從服務端單獨抽離出來,放到app.js中去。這里采用和router同樣的方式使用工廠方式,以保證每次被訪問都是一個全新的vue實例。在app.js導入剛剛寫好的路由,在每次觸發工廠的時候,創建一個新的路由實例,并綁定到vue實例里面,這樣用戶在訪問路徑的時候無論是vue實例還是router都是全新的了。

app.js:

const Vue = require("vue");const createRouter = require("./router")module.exports = (context) => {  const router = createRouter();  return new Vue({    router,    data:{      message:"Hello,Vue SSR!"    },    template:`      <div>        <h1>{{message}}</h1>        <ul>          <li>,            <router-link to="/">首頁<router-link/>          </li>          <li>            <router-link to="/about">關于我<router-link/>          </li>        </ul>      </div>      <router-view></router-view>    `   });}

做完這些東西貌似好像就能用了一樣,但是還是不行,仔細想想好像忘了一些什么操作,剛剛把vue實例從index.js中抽離出來了,但是卻沒有在任何地方使用它,哈哈,好像是一件很尷尬的事情。

修改index.js文件:

const express = require("express");const vueApp = require("./src/app.js");const vueServerRender = require("vue-server-render").creteRender();const app = express();app.get('*',(request,respones) => {    // 這里可以傳遞給vue實例一些參數  let vm = vueApp({})    respones.status(200);  respones.setHeader("Content-Type","text/html;charset-utf-8;");  vueServerRender.renderToString(vm).then((html) => {    respones.end(html);  }).catch(error => console.log(error));})app.listen(3000,() => {  console.log("服務已啟動")});

準備工作都已經做好啦,完事具備只欠東風啦?,F在運行一下npm start可以去頁面上看一下效果啦??吹巾撁嬷幸呀涗秩境鰜砹?,但是好像是少了什么?雖然導航內容已經都顯示出來了,但是路由對應的組件好像沒得渲染噻。具體是什么原因導致的呢,vue-router是由前端控制渲染的,當訪問路由的時候其實,在做首屏渲染的時候并沒有授權給服務端讓其去做渲染路由的工作。(⊙亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

欧美日韩亚洲激情| 亚洲精品美女视频| 亚洲精品中文字幕女同| 日韩成人在线电影网| 91精品中国老女人| 国产精品专区h在线观看| 精品国产91乱高清在线观看| 4438全国亚洲精品在线观看视频| 国产精品国产三级国产aⅴ9色| 色樱桃影院亚洲精品影院| 欧美成人免费播放| 97视频在线观看免费高清完整版在线观看| 久久成人国产精品| 欧美精品videossex88| 亚洲午夜性刺激影院| 日韩欧美精品免费在线| 久久夜精品va视频免费观看| www.国产一区| 国产精品观看在线亚洲人成网| 亚洲日本中文字幕| 国产精品香蕉av| 国产精品久久综合av爱欲tv| 久久久久久成人精品| 91精品国产色综合久久不卡98| 国产a∨精品一区二区三区不卡| 欧美在线视频一区| 亚洲视频在线视频| 日韩中文在线不卡| 这里只有精品丝袜| 日韩精品视频免费在线观看| 日韩中文av在线| 日韩va亚洲va欧洲va国产| 欧美日韩国产色| 亚洲最大在线视频| 亚洲理论片在线观看| 欧美一性一乱一交一视频| 国产精品国内视频| 国产日韩欧美在线| 欧美在线一区二区三区四| 欧美日韩免费在线观看| 日本精品免费观看| 亚洲黄色在线观看| 91在线免费视频| 国产成人精品免费久久久久| 国产欧美日韩中文字幕在线| 一区二区三区 在线观看视| 亚洲成年人影院在线| 亚洲欧美国产一区二区三区| 欧美多人爱爱视频网站| 中文字幕在线国产精品| 欧美在线免费视频| 亚洲美女久久久| 国产精品视频一区二区高潮| 欧美电影在线观看高清| yw.139尤物在线精品视频| 国产在线视频欧美| 国产精品久久久久久久久免费看| 欧美激情视频一区二区三区不卡| 国产91精品青草社区| 国产成人在线播放| 中文字幕国产精品久久| 欧美精品免费播放| 国产精品久久国产精品99gif| 亚洲精品国产精品乱码不99按摩| 欧美激情2020午夜免费观看| 日韩av在线电影网| 中文字幕一精品亚洲无线一区| 日韩亚洲一区二区| 国产一区玩具在线观看| 亚洲欧美综合另类中字| 亚洲电影av在线| 在线观看欧美日韩| 欧美成人三级视频网站| 91精品在线播放| 久久久精品美女| 国产成人在线播放| 欧美日韩成人在线观看| 日韩在线观看免费全集电视剧网站| 92版电视剧仙鹤神针在线观看| 亚洲国产成人在线播放| 91网在线免费观看| 色伦专区97中文字幕| 欧美日韩爱爱视频| 午夜精品久久久久久99热| 亚洲毛片在线免费观看| 日韩成人网免费视频| 欧美亚洲在线视频| 欧美成人精品三级在线观看| 欧美日韩性生活视频| 国产精品福利无圣光在线一区| 成人性教育视频在线观看| 国产精品久久在线观看| 欧美在线观看网站| 57pao国产精品一区| 韩曰欧美视频免费观看| 亚洲欧美日韩图片| 久久国产精品久久久久久| 青青在线视频一区二区三区| 国产精品久久久久久久午夜| 77777亚洲午夜久久多人| 日韩av中文字幕在线| 欧美人交a欧美精品| 一区二区三欧美| 欧美日韩国产综合视频在线观看中文| 国产精品久久久久久亚洲影视| 国产精品99久久久久久久久久久久| 欧美国产日韩免费| 中日韩美女免费视频网站在线观看| 亚洲人在线视频| 国产成人精品免费视频| 国产精品99免视看9| 高清一区二区三区日本久| 揄拍成人国产精品视频| 亚洲视频一区二区| 欧亚精品在线观看| 亚洲国产精品99久久| 日韩电影网在线| 亚洲第一区在线观看| 亚洲有声小说3d| 亚洲日韩欧美视频一区| 精品久久香蕉国产线看观看亚洲| 亚洲图片欧美日产| 久久久久久国产精品| 精品国产一区二区三区四区在线观看| 国产精品丝袜久久久久久高清| 亚洲欧美www| 日韩电影在线观看永久视频免费网站| 亚洲无线码在线一区观看| 日韩精品中文字幕视频在线| 456国产精品| 亚洲精品视频免费| 欧美成人午夜视频| 久久久精品电影| 亚洲黄色在线观看| 欧美疯狂xxxx大交乱88av| 国产精品精品久久久久久| 日韩欧美大尺度| 中文字幕亚洲激情| 亚洲高清av在线| 精品亚洲一区二区三区在线播放| 亚洲激情国产精品| 亚洲视频电影图片偷拍一区| 日韩av影片在线观看| 久久久久久久久久久亚洲| 成人在线免费观看视视频| 欧美国产日韩在线| 91精品视频免费观看| 国产精品丝袜久久久久久不卡| 91国在线精品国内播放| 91精品视频在线| 大胆欧美人体视频| 欧美日韩国产成人高清视频| 成人激情综合网| 国产日韩精品电影| 91美女片黄在线观| 国产精品日韩欧美综合| 国产成人av网址| 欧美国产高跟鞋裸体秀xxxhd| 日韩激情av在线免费观看| 成人黄色生活片| 久久精品成人欧美大片| 91九色精品视频| 在线观看国产成人av片| 久久精品男人天堂|