vue ssr 实战

SSR 概念 (server side render)

Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记”激活”为客户端上完全可交互的应用程序。

传统web渲染技术:asp.net php jsp

image-20200503233936790

SSR:

image-20200503234609398

实现vue ssr 的具体过程

创建vue cli 3

  1. vue create ssr

安装依赖

渲染器 vue-server-renderer
nodejs 服务器 express

  1. npm i vue-server-renderer express -D

编写服务端启动脚本

  1. const express = require("express")
  2. const Vue = require("vue")
  3. //创建express 和 vue 实例
  4. const app = express()
  5. //创建渲染器
  6. const renderer = require('vue-server-renderer').createRenderer()
  7. //用渲染器渲染page 可以得到 html 内容
  8. const page = new Vue({
  9. template: '<div>hello ,vue ssr</div>'
  10. })
  11. app.get("/", async (req, res) => {
  12. try {
  13. //用渲染器渲染page 可以得到 html 内容
  14. const html = await renderer.renderToString(page)
  15. console.log(html);
  16. res.send(html)
  17. } catch (error) {
  18. res.status(500).send("服务器内部错误")
  19. }
  20. })
  21. app.listen(3000, () => {
  22. console.log("server is running...");
  23. })

vue-router

  1. npm install vue-router --save

配置

  • 创建./src/router/index.js
  • 创建Index.vue、Detail.vue,更新App.vue ``` // router/index.js import Vue from ‘vue’ import Router from “vue-router”; import Index from “../components/Index”; import Detail from “../components/Detail”;

Vue.use(Router)

//这里为什么不导出一个router 实例 ? //因为:将来每次用户请求都需要用户实例 export default function createRouter(){ return new Router({ mode: ‘history’, routes: [ { path: ‘/‘, component: Index }, { path: ‘/detail’, component: Detail } ] }) }

  1. ```
  2. // App.vue
  3. <template>
  4. <div id="app">
  5. <nav>
  6. <router-link to="/">首页</router-link>
  7. <router-link to="/detail">详情页</router-link>
  8. </nav>
  9. <router-view></router-view>
  10. </div>
  11. </template>
  12. <script>
  13. export default {};
  14. </script>
  15. <style>
  16. </style>

构建

构建流程

image-20200504132616680

代码结构

image-20200504132645686

入口 :app.js

  1. // app.js
  2. // 创建vue实例
  3. import Vue from "vue";
  4. import App from "./App";
  5. import createRouter from "./router";
  6. //这里为什么使用工厂函数 ?
  7. //因为:将来每次用户请求都需要用户实例
  8. export default function createApp() {
  9. const router = new createRouter()
  10. const app = new Vue({
  11. router,
  12. render: h => h(App)
  13. })
  14. return { app, router }
  15. }

服务端入口

entry-server.js

  1. // 渲染首屏
  2. import createApp from "./app";
  3. // context 是什么 ?
  4. export default context => {
  5. return new Promise((resolve, reject) => {
  6. const { app, router } = createApp();
  7. //进入首屏去
  8. router.push(context.url)
  9. router.onReady(() => {
  10. resolve(app)
  11. },reject)
  12. })
  13. }

客户端入口

entry-client.js

  1. //挂载、激活app
  2. import createApp from "./app";
  3. const { app, router } = createApp()
  4. router.onReady(() => {
  5. app.$mount('#app')
  6. })