美文网首页
Vue SSR demo

Vue SSR demo

作者: 南枫小谨 | 来源:发表于2021-05-21 21:46 被阅读0次

vue ssr

创建工程 vue cli3

   vue create ssr

安装依赖

   vue-server-renderer // 渲染器
   express  // nodejs 服务器
   npm i vue-server-renderer express -D

编写服务端脚本

    // nodejs 服务器
    const express = require('express')
    const Vue = require('vue')
    // 创建 express 与vue 实例
    const app = express()
    // 创建渲染实例
    const renderer = require('vue-server-renderer').createRenderer()
    // 将来将Vue 传给渲染器的实例会得到一个html 内容
    const page= new Vue({
        data:{title:'服务端渲染'},
        template:'<div>{{title}},vue ssr</div>'
    })
    app.get('/',async(req,res)=>{
        try {
            const html = await renderer.renderToString(page)
            res.send(html)
        } catch (error) {
            res.status(500).send('服务器内部错误')
        }
    
    })
    app.listen(3000,()=>{
        console.log('渲染服务器启动成功!')
    })

采用vue-router

  1. src下新建一个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. components 下新建两个文件
    Detail.js
<template >
    <div>
        Detail Page
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang='scss' scoped>

</style>

Index.js

<template >
    <div>
        index Page
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang='scss' scoped>

</style>

修改App.vue

<template>
  <div id="app">
   <nav>
     <router-link to='/'>首页</router-link>
     <router-link to='/detail'>详情页</router-link>
   </nav>
   <router-view></router-view>
  </div>
</template>

入口

// 创建vue 实例
import Vue from 'vue'
import App from './App.vue'
import createRouter from './router'
export default function createApp(){
    const router = createRouter()
    const app = new Vue({
        router,
        render:h=>h(App)
    })
    return {app,router}
}

服务端入口

// 渲染首屏幕
import createApp from './app'
export default context=>{
    return Promise((resolve,reject)=>{
        const {app,router} = createApp()
        // 进入首屏
        router.push(context.url)
        router.onReady(()=>{
            resolve(app)
        },reject)
    })
}

客户端入口

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

webpack 打包
npm i webpack-node-externals lodash.merge -D

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 = {
    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
            });
        });

    }
}

打包脚本
npm i cross-env -D

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

新建一个template 作为服务端渲染的模版 index.temp.html

<!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>

服务端渲染 脚本 更改

// nodejs 服务器
const express = require('express')
const Vue = require('vue')
const fs = require('fs')
// 创建 express 与vue 实例
const app = express()
// 创建渲染实例
const {createBundleRenderer} = require('vue-server-renderer')
// 服务端bundle
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:'ssr test'
        }
        const html = await renderer.renderToString(context)
        res.send(html)
    } catch (error) {
        res.status(500).send('服务器内部错误')
    }
 
})
app.listen(3000,()=>{
    console.log('渲染服务器启动成功!')
})

相关文章

网友评论

      本文标题:Vue SSR demo

      本文链接:https://www.haomeiwen.com/subject/xtsgjltx.html