1. 程式人生 > >vue-ssr的實現原理連載(一)

vue-ssr的實現原理連載(一)

前言: 

 服務端渲染,簡明的說就是在服務端獲取資料並進行解析渲染,直接生成html片段返回給瀏覽器。

  優缺點: 

  服務端渲染能解決的問題: 1.SEO問題,前端動態渲染的內容是不能被搜尋蜘蛛抓取的。2.首屏載入過程慢。SPA在初始化首屏的時候需要載入所有的資源,這也是使用服務端渲染能折中解決的問題。 

  服務端渲染的缺點:1.增加伺服器的壓力。 2.同構似乎對前後端分離有所違背

 

vue-server-renderer

  文件地址: https://ssr.vuejs.org/en/   暫時沒有中文文件。下面來一步一步的說明實現過程。所有的原始碼都可以在我github上檢視,並且根據教程分了step,歡迎star。

  vue-ssr的實現原理連載(一): https://github.com/Jasonwang911/vue-ssr/tree/master/step1

 

首先安裝相關依賴: 

npm init -y

yarn add koa koa-router koa-static vue vue-router vuex vue-server-renderer

 

先要確定vue的版本

vue & vue-server-renderer 2.3.0+
vue-router 2.5.0+
vue-loader 12.0.0+ & vue-style-loader 3.0.0+
vue-server-renderer 是vue官方用來實現vue服務端渲染的一個包。具體官方教程是: https://ssr.vuejs.org/zh/#%E4%BB%80%E4%B9%88%E6%98%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E6%B8%B2%E6%9F%93-ssr-%EF%BC%9F

新建server.js檔案,然後編寫一個最簡單的koa服務
const Koa = require("koa");
const Router = require("koa-router");
const Static = require("koa-static");

const app = new Koa();
const router = new Router();

router.get("/", ctx => {
  ctx.body = "hello vue-ssr";
});

app.use(router.routes());

app.listen(3000, () => {
  console.log(`node serve run at port 3000`);
});

 

使用nodemon啟動  nodemon server.js, 開啟瀏覽器的 localhost:3000埠,可以看到 hello vue-ssr。

接下來,我們來進行一些改造,引入vue, 來建立一個vue的例項,然後引入 vue-server-renderer ,來去渲染我們的vue例項。這裡需要注意兩點, 1. 建立的vue的例項是在服務端使用的,所以並不能掛載元素,只能渲染template模板字串   2. vue-server-renderer 這個包可以幫我們建立一個渲染器render, 渲染器有很多方法 render.renderToString()  渲染成字串,render.renderToStream 渲染成流等等。需要注意的是 render.renderToString() 接收一個vue的例項並返回一個promise的字串,將返回的字串直接渲染到頁面上,注意這個方法是個非同步操作。

 
const Koa = require("koa");
const Router = require("koa-router");
const Static = require("koa-static");
const Vue = require("vue");
const VueServerRender = require("vue-server-renderer");

// 建立一個vue的例項,注意在服務端不能掛載元素,只能使用渲染模板字串
const vm = new Vue({
  data() {
    return {
      msg: "hello vue-ssr"
    };
  },
  template: `<div>{{msg}}</div>`
});

// 建立一個渲染器
let render = VueServerRender.createRenderer();

const app = new Koa();
const router = new Router();

// render.renderToString() 接收一個vue的例項並返回一個promise的字串,將返回的字串直接渲染到頁面上,注意這個方法是個非同步操作
router.get("/", async ctx => {
  ctx.body = await render.renderToString(vm);
});

app.use(router.routes());

app.listen(3000, () => {
  console.log(`node serve run at port 3000`);
});

  

儲存,nodemon 會自動幫我們更新服務,然後瀏覽器上仍舊會顯示 hello vue-ssr, 所不同的是在檢視網頁原始碼的時候,是以下的內容:  
<div data-server-rendered="true">hello vue-ssr</div>

  

data-server-rendered="true" 的作用會在後面的小結說明,是為了效能的考慮,告訴瀏覽器這個是服務端渲染的,不需要進行diff操作,以節省效能的目的。

檢視完原始碼,你可能會說,這個缺少一個基本的html的頁面結構,現在我們就來一起實現: 

首先,render渲染函式可以接受引數,引數中的template便是模板,我們可以將render.renderToString(vm)的結果插入到模板中的指定位置中去。這個指定位置是通過一個註釋標明的,首先我們建立模板檔案 template.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>vue-ssr</title>
  </head>
  <body>
    <!-- vue-ssr-outlet -->
  </body>
</html>

  

<!-- vue-ssr-outlet --> 就是標明服務端渲染後的字串 <div data-server-rendered="true">hello vue-ssr</div> 將要插入的位置。

然後我們在koa服務中讀取模板檔案,並在渲染函式中配置這個模板檔案,讀取模板檔案使用了node的fs模組:

const fs = require("fs");

const template = fs.readFileSync("./template.html", "utf8");

 

完整程式碼: 

server.js

const Koa = require("koa");
const Router = require("koa-router");
const fs = require("fs");
const Static = require("koa-static");
const Vue = require("vue");
const VueServerRender = require("vue-server-renderer");

// 建立一個vue的例項,注意在服務端不能掛載元素,只能使用渲染模板字串
const vm = new Vue({
  data() {
    return {
      msg: "hello vue-ssr"
    };
  },
  template: `<div>{{msg}}</div>`
});

const template = fs.readFileSync("./template.html", "utf8");
// 建立一個渲染器
let render = VueServerRender.createRenderer({
  template
});

const app = new Koa();
const router = new Router();

// render.renderToString() 接收一個vue的例項並返回一個promise的字串,將返回的字串直接渲染到頁面上,注意這個方法是個非同步操作
router.get("/", async ctx => {
  ctx.body = await render.renderToString(vm);
});

app.use(router.routes());

app.listen(3000, () => {
  console.log(`node serve run at port 3000`);
});

  

template.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>vue-ssr</title>
  </head>
  <body>
    <!--vue-ssr-outlet-->
  </body>
</html>

 

第一部分就到這裡。