Vue SSR服务端渲染

一、一个最简单的vue SSR demo

1. 安装vue-server-renderer express

npm i vue-server-renderer express -D

2.在根目录下创建server.js

const express = require('express')
const app = express()
const Vue = require('vue')
const renderer = require('vue-server-renderer').createRenderer()

app.get('/', (req, res) => {
    const vm = new Vue({
        template: `<div>hello ssr</div>`
    })
    renderer.renderToString(vm).then(html => {
        res.send(html)
    })
})

app.listen(3000, () => {
    console.log('服务器启动了!')
})

3. 执行node, 访问3000端口

node ./server.js

 二、在项目一的基础上修改(添加router)

1. 创建src/router/index.js

const Vue = require('vue')
const VueRouter = require('vue-router')

Vue.use(VueRouter);

const routes = [{
        path: "/",
        name: "home",
        component: {
            template: `<div>hello page</div>`
        },
    },
    {
        path: "/about",
        name: "about",
        component: {
            template: `<div>about page</div>`
        }
    },
];

module.exports = function createRouter() {
    return new VueRouter({
        mode: "history",
        routes,
    });
}

2.创建src/app.js

const Vue = require('vue')
const createRouter = require('./router')


Vue.config.productionTip = false

module.exports = function createApp(context) {
    const router = createRouter()
    const app = new Vue({
        router,
        data: {
            msg: 'hello ssr'
        },
        template: `
            <div>
                <h1>{{msg}}</h1>
                <nav>
                    <router-link to="/">Home</router-link> |
                    <router-link to="/about">About</router-link>
                </nav>
                <router-view/>
            </div>
        `
    })
    return {
        app,
        router
    }
}

3. 创建src/entry-server.js

const createApp = require('./app.js')

module.exports = (context) => {
    return new Promise(async(resolve, reject) => {
        let { url } = context
        let { app, router } = createApp(context)
        router.push(url);
        router.onReady(() => {
            resolve(app)
        }, reject)
    })
}

4. 创建src/entry-client.js

const createApp = require('./app.js')
const { app, router } = createApp(context)

router.onReady(() => {
    app.$mount('#app')
})

5. 在/根目录下创建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>Hello, SSR</title>
</head>

<body>
    <!--vue-ssr-outlet-->
</body>

</html>

6.修改/server.js

const express = require('express')
const app = express()
const path = require('path')
const fs = require('fs')
const renderer = require('vue-server-renderer').createRenderer({
    template: fs.readFileSync(path.join(__dirname, './index.html'), 'utf-8')
})
const App = require('./src/entry-server.js')

app.get('*', async(req, res) => {
    const { url } = req
    const vm = await App({ url })
    renderer.renderToString(vm).then(html => {
        res.send(html)
    }).catch(err => console.log(err))
})

app.listen(3000, () => {
    console.log('服务器启动了!')
})

7.执行node ./server.js 访问localhost:3000,到此为止router就可以切换页面了

三、通过webpack打包

1、通过vue-cli创建项目

2、安装以下库

npm i webpack-node-externals lodash.merge cross-env express vue-server-renderer -D

3、在根目录下创建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>Hello, SSR</title>
</head>

<body>
    <!--vue-ssr-outlet-->
</body>

</html>

4、创建/src/app.js

import Vue from 'vue'
import createRouter from './router'
import App from './App.vue'

Vue.config.productionTip = false

export default function createApp() {
    const router = createRouter()
    const app = new Vue({
            router,
            render: h => h(App)
        })
    return {
        app,
        router
    }
}

5、创建/src/router/index.js

import Vue from "vue";
import VueRouter from "vue-router";
import HomeView from '@/views/HomeView.vue'
import AboutView from '@/views/AboutView.vue'

Vue.use(VueRouter);

const routes = [{
        path: "/",
        name: "home",
        component: HomeView
    },
    {
        path: "/about",
        name: "about",
        component: AboutView
    },
];

// 返回一个创建router的方法
export default function createRouter() {
    return new VueRouter({
        mode: "history",
        routes,
    });
}

6、创建/src/entry-server.js

import createApp from './app.js'

export default (context) => {
    return new Promise(async(resolve, reject) => {
        let { url } = context
        let { app, router } = createApp(context)
        router.push(url);
        // 进入首屏
        router.onReady(() => {
            resolve(app)
        }, reject)
    })
}

7、创建/src/entry-client.js

import createApp from './app.js'

const { app, router } = createApp(context)

router.onReady(() => {
    app.$mount('#app')
})

8、创建/server,js

const express = require('express')
const app = express()
const path = require('path')
const fs = require('fs')
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(path.join(__dirname, './index.html'), 'utf-8'),
    clientManifest
})

app.get('*', async(req, res) => {
    try {
        const context = {
            url: req.url,
            title: 'ssr test'
        }
        const html = await renderer.renderToString(context);
        // eslint-disable-next-line no-console
        console.log(html);
        res.send(html);
    } catch (error) {
        res.status(500).send("服务器内部错误");
    }
})

app.listen(3000, () => {
    console.log('服务器启动了!')
})

9、修改vue.config.js

const { defineConfig } = require('@vue/cli-service')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
const nodeExternals = require('webpack-node-externals')
const merge = require('lodash.merge')
const TARGET_NODE = process.env.WEBPACK_TARGET === 'node'
const target = TARGET_NODE ? 'server' : 'client'

module.exports = defineConfig({
    transpileDependencies: true,
    css: {
        extract: false
    },
    outputDir: './dist/' + target,
    configureWebpack: () => ({
        entry: `./src/entry-${target}.js`,
        devtool: 'source-map',
        target: TARGET_NODE ? 'node' : 'web',
        node: TARGET_NODE ? undefined : false,
        output: {
            libraryTarget: TARGET_NODE ? 'commonjs2' : undefined
        },
        externals: TARGET_NODE ?
            nodeExternals({
                allowlist: [/\.css$/]
            }) : undefined,
        optimization: {
            splitChunks: TARGET_NODE ? false : undefined
        },
        plugins: [TARGET_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()]
    }),
    chainWebpack: config => {
        config.module
            .rule('vue')
            .use('vue-loader')
            .tap(options => {
                merge(options, {
                    optimizeSSR: false
                })
            })
    }
})

10、修改package.json的打包命令

    "scripts": {
        "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"
    },

11、 通过npm run build进行打包

12、执行node ./server.js运行express server, 访问localhost:3000

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值