Vue SSR 指南(二)

Vue SSR 指南(二)

根据官网按步骤实现Vue SSR搭建过程

使用 webpack 的源码结构(vue-cli3)

新建一个项目,使用vue-cli3脚手架搭建,vue create ssr-demo-webpack 根据自己需求选择,项目结构如下:

在这里插入图片描述

1.main.js

main.js 是我们应用程序的「通用 entry」。在纯客户端应用程序中,我们将在此文件中创建根 Vue 实例,并直接挂载到 DOM。但是,对于服务器端渲染(SSR),责任转移到纯客户端 entry 文件。main.js 简单地使用 export 导出一个 createApp 函数:

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

// 导出一个工厂函数,用于创建新的
// 应用程序、router 和 store 实例
export function createApp() {
  const app = new Vue({
    // 根实例简单的渲染应用程序组件。
    render: (h) => h(App),
  })
  return { app }
}


2.entry-client.js

客户端 entry 只需创建应用程序,并且将其挂载到 DOM 中:

import { createApp } from './main'

// 客户端特定引导逻辑……

const { app, router } = createApp()

// 这里假定 App.vue 模板中根元素具有 `id="app"`
router.onReady(() => {
  app.$mount('#app')
})

3.entry-server.js

服务器 entry 使用 default export 导出函数,并在每次渲染中重复调用此函数。此时,除了创建和返回应用程序实例之外,它不会做太多事情 - 但是稍后我们将在此执行服务器端路由匹配 (server-side route matching) 和数据预取逻辑 (data pre-fetching logic)。

import { createApp } from './app'

export default context => {
  const { app } = createApp()
  return app
}

架构

过程简述
entry-server.js构建后成为 vue-ssr-server-bundle.json文件(vue代码) server.js将 vue-ssr-server-bundle.json (vue代码)注入到模版文件中,并输出,暂时未用到 entry-client.js

4.构建配置
npm install cross-env webpack-node-externals vue-server-renderer --save-dev

调整 webpack 配置最简单的方式就是在 vue.config.js 中的 configureWebpack 选项提供一个对象,
该对象将会被 webpack-merge 合并入最终的 webpack 配置。

注意点:不修改以下配置编译报错
​ 1.allowlist: [/.css$/], // [webpack-node-externals] : Option ‘whitelist’ is not supported. Did you mean ‘allowlist’?
​ 2. splitChunks: TARGET_NODE ? false : undefined, //不配置报错 Server-side bundle should have one single entry file. Avoid using CommonsChunkPlugin in the server config. vuessr 报错解决

const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')

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

module.exports = {
  configureWebpack: () => {
    if (process.env.WEBPACK_TARGET === 'node') {
      return {
        entry: './src/entry-server.js',
        target: 'node',
        devtool: 'source-map',
        output: {
          libraryTarget: 'commonjs2',
        },
        externals: [
          nodeExternals({
            allowlist: [/\.css$/], // [webpack-node-externals] : Option 'whitelist' is not supported. Did you mean 'allowlist'?
          }),
        ],
        optimization: {
          splitChunks: TARGET_NODE ? false : undefined, //不配置报错 Server-side bundle should have one single entry file. Avoid using CommonsChunkPlugin in the server config. vuessr 报错解决
        },
        plugins: [new VueSSRServerPlugin()],
      }
    } else {
      return {
        entry: './src/entry-client.js',
        plugins: [new VueSSRClientPlugin()],
      }
    }
  },
}

5.修改package.json
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build:client": "vue-cli-service build",
    "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build --mode server",
    "build:win": "npm run build:server && move dist\\vue-ssr-server-bundle.json bundle && npm run build:client && move bundle dist\\vue-ssr-server-bundle.json",
    "build:mac": "npm run build:server && mv dist/vue-ssr-server-bundle.json bundle && npm run build:client && mv bundle dist/vue-ssr-server-bundle.json"
  },

根据自己系统运行 npm run build:win或者npm run build:mac`,会在根目录下生成dist文件夹

在这里插入图片描述

6.服务端

新建server.js

const serverBundle = require('./dist/vue-ssr-server-bundle.json')
const express = require('express')
const app = express()
const path = require('path')
const renderer = require('vue-server-renderer').createBundleRenderer(serverBundle, {
  template: require('fs').readFileSync('./index.template.html', 'utf-8'),
})

app.get('*', (req, res) => {
  const context = {
    title: 'ssr',
    meta: `
    <meta charset="utf-8">
    `,
    url: req.url,
  }
  renderer.renderToString(context, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.end(html)
  })
})

app.listen(8080, () => {
  console.log('已监听 localhost:8080')
})


新建

index.template.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- 使用三花括号(triple-mustache)进行 HTML 不转义插值(non-HTML-escaped interpolation) -->
    {{{ meta }}}
    <!-- 使用双花括号(double-mustache)进行 HTML 转义插值(HTML-escaped interpolation) -->
    <title>{{ title }}</title>
  </head>

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

运行node server.js,并打开浏览器(因为还未用到router,所以home|about不可跳转路由)

在这里插入图片描述

7.源码

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值