vue2-ssr从vue-cli搭建项目改造服务端渲染+打包上线部署

1.通过 vue-cli 创建 vue 项目

复制代码
vue create 项目名称

2.进入项目安装vue服务端渲染插件vue-server-renderer

复制代码
npm install vue-server-renderer -S

vue-server-renderer和vue必须匹配版本

vue-server-renderer依赖一些Node.js原生提供的api,因此需要配合Node.js使用

3.更改router/index.js代码

复制代码
import Vue from "vue"
import Router from "vue-router"

import Home from "@/components/Home"
import About from "@/components/About"

Vue.use(Router)

//每次用户请求都需要创建一个新的router实例
//创建createRouter工厂函数
export default function createRouter() {
    //创建router实例
    return new Router({
        mode: "history",
        routes: [
            {
                path: "/", 
                name: 'home',
                component: Home
            },
            {
                path: "/about", 
                name: 'about',
                component: About
            }
        ]
    })
}

4.修改 App.vue

复制代码
<template>
  <div id="app">
    <nav>
      <router-link to="/">首页</router-link>
      <router-link to="/about">关于</router-link>
    </nav>
    <router-view></router-view>
  </div>
</template>

5.main.js文件

复制代码
import Vue from "vue"
import App from "./App.vue"
import createRouter from "./router"

//创建createApp工厂函数
export default function createApp() {
    const router = createRouter()
    //创建vue实例
    const app = new Vue({
        router,
        render: h => h(App),
    })
    return { app, router }
}

6.在src目录下创建服务端入口entry-server.js用于渲染首屏

复制代码
import createApp from "./app"

//context就是地址
export default context => {   
    return new Promise((resolve, reject) => {
        const { app, router } = createApp()
        //渲染首屏
        router.push(context.url)
        router.onReady(() => {
            resolve(app)
        }, reject)
    })
}

7.在src目录下创建客户端入口entry-client.js用于挂载激活 app

复制代码
import createApp from "./app"

const { app, router } = createApp()
router.onReady(() => {
    //挂载激活app
    app.$mount("#app")
})

8.创建页面模板index.temp.html

在 public 目录下创建 index.temp.html ,作为渲染 Vue 应用程序时,renderer 生成 HTML 页面包裹容器,来包裹生成的 HTML 标记

vue-ssr-outlet那一坨注释,中间不能有空格!!不然会出问题

通过服务端渲染好的文档节点内容,就是放在那里的

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue ssr</title>
</head>
<body>
    <!--vue-ssr-outlet-->
</body>
</html>

9.创建 Node.js web服务器

这里我使用的是express,它是基于原生node的web服务器做了二次的封装,因为原生的node代码比较多,新手可能不太容易理解

使用以下命令安装express

复制代码
npm install express --save

安装完成后在项目根目录下创建 server.js 文件贴入以下代码,用于搭建web服务器

复制代码
//nodejs服务器
const express = require("express")
const Vue = require("vue")
const fs = require("fs")

//创建express实例
const app = express()
//创建渲染器
const { createBundleRenderer } = require("vue-server-renderer")
const serverBundle = require("./dist/server/vue-ssr-server-bundle.json")
const clientManifest = require("./dist/client/vue-ssr-client-manifest.json")
const renderer = createBundleRenderer(serverBundle, {
    runInNewContext: false,
    template: fs.readFileSync("./public/index.temp.html", "utf-8"), //页面模板
    clientManifest
})

//中间件处理静态文件请求
app.use(express.static("./dist/client", {index: false}))

//将路由的处理交给vue
app.get("*", async (req, res) => {
    try {
        const context = {
            url: req.url,
            title: ""
        }
        //````````````渲染一个string类型的Vue实例(内容少时)````````````````
        // const html = await renderer.renderToString(context)
        // res.send(html)
        //````````````渲染一个流模式的Vue实例(内容多时)````````````````````
        const ssrStream = await renderer.renderToStream(context)
        const buffers = []
        ssrStream.on("data", (data) => {
            buffers.push(data)
        })
        ssrStream.on("end", () => {
            res.end(Buffer.concat(buffers))
        })
    }catch {
        res.status(500).send("服务器内部错误!")
    }
})

app.listen(9999, () => {
    console.log("服务器渲染成功!")
})

10.修改vue.config.js配置

复制代码
const VueSSRServerPlugin = require("vue-server-renderer/server-plugin")
const VueSSRClientPlugin = require("vue-server-renderer/client-plugin")

//环境变量,决定入口是客户端还是服务端
const TARGRT_NODE = process.env.WEBPACK_TARGET === "node"
const target = TARGRT_NODE ? "server" : "client"

module.exports = {
    css: {
        extract: false
    },
    outputDir: "./dist/" + target,
    configureWebpack: () => ({
        //将 entry 指向应用程序的 server entry 文件
        entry: `./src/entry-${target}.js`,
        //对 bundle renderer 提供 source map 支持
        devtool: "source-map",
        //这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import)
        //并且还会在编译 Vue 组件时,告知 `vue-loader` 输送面向服务器代码(server-oriented code)
        target: TARGRT_NODE ? "node" : "web",
        node: TARGRT_NODE ? undefined : false,
        output: {
            //此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)
            libraryTarget: TARGRT_NODE ? "commonjs2" : undefined
        },
        optimization: { splitChunks: TARGRT_NODE ? false : undefined },
        //将服务器的整个输出构建为单个 JOSN 文件的插件
        //服务端默认文件名为 vue-ssr-server-bundle.json
        plugins: [TARGRT_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()]
    })
}

11.配置打包脚本

安装cross-env 插件:运行跨平台设置和使用环境变量的脚本

复制代码
npm install cross-env --save

在 package.json 文件中,scripts选项下,添加以下脚本

复制代码
"scripts": {
    "server": "node server",
    "build:client": "vue-cli-service build",
    "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build --mode server",
    "build": "npm run build:server && npm run build:client"
},

开发完成后

12.打包项目:

复制代码
npm run build

13.打包完成后,在终端执行命令启动web服务器

复制代码
npm run server

在浏览器打开http://localhost:9999即可访问,9999为server.js里面我设置的端口号,可以改成自己想设置的端口

14.发布上线前准备

新建一个文件夹,将以下内容复制到新文件夹下

package.json文件,打包后的dist文件夹,server.js文件

15.部署

在服务器安装node,将新文件夹放入相关公司要求的位置,在项目目录执行npm i安装依赖,然后npm run server启动服务即可

注意!项目上线运行时需保持express服务器持续开启

相关推荐
sunshine6414 分钟前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻28 分钟前
Vue(四)
前端·javascript·vue.js
蜜獾云30 分钟前
npm淘宝镜像
前端·npm·node.js
dz88i830 分钟前
修改npm镜像源
前端·npm·node.js
Jiaberrr34 分钟前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook
程序员_三木1 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
顾平安2 小时前
Promise/A+ 规范 - 中文版本
前端
聚名网2 小时前
域名和服务器是什么?域名和服务器是什么关系?
服务器·前端
桃园码工2 小时前
4-Gin HTML 模板渲染 --[Gin 框架入门精讲与实战案例]
前端·html·gin·模板渲染
不是鱼2 小时前
构建React基础及理解与Vue的区别
前端·vue.js·react.js