陌小路的个人博客 陌小路的个人博客
首页
  • 技术专区

    • 面试
    • Vue
    • Electron
    • TypeScript
    • Serverless
    • GraphQL
  • 我的秋招之旅
  • 2019年终总结
Todo
收藏夹
关于作者
GitHub

陌小路

前端切图仔
首页
  • 技术专区

    • 面试
    • Vue
    • Electron
    • TypeScript
    • Serverless
    • GraphQL
  • 我的秋招之旅
  • 2019年终总结
Todo
收藏夹
关于作者
GitHub
  • Vue

    • Vue3-beta-初体验
    • Vue-nextTick源码分析
    • Vuex-源码分析01
    • Vuex-源码分析02
    • Vite源码分析
    • Vue服务端渲染

      • 介绍
      • 快速上手
      • Vue项目添加SSR
      • 服务端搭建
        • 一键式启动项目与热更新
        • 总结
      • Petite-Vue
    • React

    • 面试

    • Electron

    • Serverless

    • GraphQL

    • TypeScript

    • RxJS

    • 工程化

    • Webpack

    • Nestjs

    • WebRTC & P2P

    • Docker

    • Linux

    • Git

    • Svelte

    • 踩坑日记 & 小Tips

    • 其他

    • technology
    • Vue
    陌小路
    2021-01-28

    服务端搭建

    在讲解完webpack相关配置的编写之后,我们就需要搭建我们用于提供渲染能力的服务端代码了。

    # Server端

    这里我们在上代码之前,我们先需要理一理思路,先回顾一下我们前面实现的一个小型的服务端渲染过程,也就是直接在服务端代码中new一个Vue实例,接着调用createBundleRenderer创建一个renderer,然后使用renderer.renderToString方法进行渲染,所以,整体流程大致为:

    1. 获取实例。
    2. 创建renderer。
    3. 执行渲染。
    4. 返回给客户端。

    就以上流程而言,我们这里的方式其实差不多,只不过在各步骤中需要做一些额外的操作。

    以下服务端代码文件位于VueSSR-Lesson项目下lessons目录

    # 获取项目代码

    // lesson2.js
    let clientManifest = require(path.resolve(__dirname, '../dist', 'vue-ssr-client-manifest.json'));
    let serverBundle = require(path.resolve(__dirname, '../dist', 'vue-ssr-server-bundle.json'));
    
    1
    2
    3

    首先我们根据前面配置的客户端与服务端相关构建的配置,分别打包构建完并待相关结果输出到dist目录下之后,就可以直接在服务端代码中将客户端配置构建的manifest文件与服务端配置构建的bundle文件进行导入,后续会需要配合生成renderer。

    # 创建renderer

    const { createBundleRenderer } = require('vue-server-renderer');
    const template = fs.readFileSync('./index.html', 'utf-8')
    const renderer = createBundleRenderer(serverBundle, {
      template,
      clientManifest,
      runInNewContext: false
    });
    
    1
    2
    3
    4
    5
    6
    7

    这里主要用到了vue-server-renderer的createBundleRenderer,并读取了一个模板文件template用于渲染,按照相关配置参数,分别传入serverBundle和clientManifest,同时,设置runInNewContext为false,这一步主要是让关闭所有请求自动创建一个新的上下文,这种方式可以减少服务器的压力,毕竟对于服务端而言,如果在请求量过多的情况下,这种方式开销会比较大。

    # 执行渲染&返回给客户端

    app.use(express.static(path.resolve(__dirname, '../dist')));
    router.get('*', (req, res) => {
        const context = { url: req.url };
        renderer.renderToString(context, (err, html) => {
            if (err) {
                if (err.code === 404) {
                    return res.end('404 Not Found');
                }
                console.log(err)
            };
            res.setHeader('Content-Type', 'text/html')
            res.send(html);
        })
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    这里为了方便就直接将dist目录开放为静态资源目录了,同时拦截所有请求执行渲染逻辑,将渲染成功后的结果发送给客户端进行展示。

    首先我们可以关注一下这个context对象,内容主要是一个请求的url,主要用于获取当前用户请求的路由,做一些数据预取的操作,具体使用这个context的代码可以参见前面的服务端entry-server.js文件,入参context就是这个地方的context对象,这里会自动调用我们的服务端打包出来的入口方法,获取到我们整个业务代码的实例(参见我们在entry-server.js中resolve的app实例),这样我们就能正确渲染出我们想要的页面了。

    得到渲染后的结果之后,我们就能直接调用express为我们提供的send方法或end方法给客户端返回结果了。

    # 完整代码

    const { createBundleRenderer } = require('vue-server-renderer');
    const express = require('express');
    const app = express();
    const router = express.Router();
    const chalk = require('chalk');
    const fs = require('fs');
    const template = fs.readFileSync('./index.html', 'utf-8')
    const path = require('path');
    let clientManifest = require(path.resolve(__dirname, '../dist', 'vue-ssr-client-manifest.json'));
    let serverBundle = require(path.resolve(__dirname, '../dist', 'vue-ssr-server-bundle.json'));
    
    app.use(express.static(path.resolve(__dirname, '../dist')));
    
    const renderer = createBundleRenderer(serverBundle, {
        template,
        clientManifest,
        runInNewContext: false
    });
    
    router.get('*', (req, res) => {
        const context = { url: req.url };
        renderer.renderToString(context, (err, html) => {
            if (err) {
                if (err.code === 404) {
                    return res.end('404 Not Found');
                }
                console.log(err)
            };
            res.setHeader('Content-Type', 'text/html')
            res.send(html);
        })
    })
    
    app.use(router);
    
    app.listen(3000, function() {
        console.log(
            'App runing at:',
            `Local: ${ chalk.blueBright.underline('http://localhost:3000') }`
        )
    });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41

    # 预览效果

    预览.png

    直接通过node执行该文件,我们就能通过浏览器访问到我们的应用了。

    在启动服务之前,请确保你的客户端manifest文件和服务端构建bundle已经构建完毕了,如果没有请先构建一下,也就是前面提到的webpack配置的两份打包配置文件。

    编辑
    上次更新: 2023/11/25, 4:11:00
    Vue项目添加SSR
    一键式启动项目与热更新

    ← Vue项目添加SSR 一键式启动项目与热更新→

    最近更新
    01
    github加速
    01-01
    02
    在线小工具
    01-01
    03
    Lora-Embeddings
    11-27
    更多文章>
    Theme by Vdoing | Copyright © 2020-2024 STDSuperman | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式