vue+ssr+koa实现,首屏快速展示以及seo优化

6 篇文章 1 订阅


一、问题

当我们平时开发vue项目,开发到一定程度的时候,内容会越来越多,打包出来的包会越来越大,亦或者首页加载的资源很多,导致用户首次加载项目页面的时候会有一段时间白屏,给人的交互不好,那么我们应该怎么去处理呢?

现在介绍一种可以首次加载项目页面达到快速展示出来的方法,那就是服务器端渲染-SSR。


二、SSR是什么?(服务器端渲染)

官方例子:vue ssr

SSR就是把vue项目打包(build)好之后,放在node服务上部署,当访问项目url的时候,直接请求node的服务,处理页面路由的内容生成好html(包括各种dom结构之类的),返回html字符串给客户端(浏览器)直接渲染。
流程:浏览器 =》 服务器 =》 html =》 页面展示

往常使用nginx部署vue项目,请求页面的流程是:
流程:浏览器 =》 服务器 =》 html =》 加载js 、生成dom =》 页面展示

纯属个人简单理解,如有错误请指正


二、搭建步骤

1.创建普通vue2项目

vue create vue-ssr-demo

2.下载相关依赖包

npm install cross-env
npm install koa
npm install koa-router
npm install koa-send
npm install vue-server-renderer
npm install webpack-node-externals

3.代码改造

1.改造src/main.js

import Vue from 'vue'
import router from './router'
import App from './App.vue'
Vue.config.productionTip = false

// 实例 每次请求都会创建新的实例
export const createApp = (context) => {
  const app = new Vue({
    router,
    context,
    render:h => h(App)
  })
  return { router, app }
}

2.增加src/client.js

客户端打包入口

//客户端打包入口文件
import {createApp} from './main'
const {app,router} = createApp();
//路由完成之后,再去进行挂载,以防有异步路由的情况
router.onReady(()=>{
    app.$mount("#app");
})

3.增加src/server.js

服务端打包入口

//服务器端打包入口文件
import { createApp } from './main'
//返回一个函数,接收请求上下文,返回创建的vue实例
//根据返回的内容,拿到指定的路由节点
export default context => {
    //这里返回一个Promise,确保路由会组件准备就绪
    return new Promise((resolve, reject) => {
        const { app, router } = createApp(context);
        //跳转到首屏地址
        router.push(context.url);
        //路由就绪,返回结果
        router.onReady(() => {
            // 访问路径,可定匹配到组件
            let matchedCompoents = router.getMatchedComponents();
            if (!matchedCompoents.length) {
                return reject({ code: 404 })
            }
            resolve(app)
        }, reject);
    })
}

4.项目目录下增加vue.config.js

// vue.config.js
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
const nodeExternals = require('webpack-node-externals')
const env = process.env
const isServer = env.RUN_ENV === 'server'

module.exports = {
  publicPath: './',
  outputDir: `dist/${env.RUN_ENV}`,
  assetsDir: 'static',
  configureWebpack: {
    // 将 entry 指向应用程序的 server / client 文件
    entry: `./src/${env.RUN_ENV}.js`,
    devtool: 'eval',
    target: isServer ? 'node' : 'web',
    // 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)
    output: {
      libraryTarget: isServer ? 'commonjs2' : undefined
    },
    externals: isServer ? nodeExternals({
      allowlist: /\.css$/
    }) : undefined,
    optimization:{splitChunks:isServer ? false : undefined},
    // 这是将服务器的整个输出
    // 构建为单个 JSON 文件的插件。
    // 服务端默认文件名为 `vue-ssr-server-bundle.json`
    // 客户端默认文件名为 `vue-ssr-client-manifest.json`
    plugins: [
      isServer ? new VueSSRServerPlugin() : new VueSSRClientPlugin(),
    ]
  }
}

5.项目目录下增加index.ssr.html

<!–vue-ssr-outlet–>为注入标记

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>ssr-test</title>
  </head>
  <body>
    <div id="app">
      <!--vue-ssr-outlet-->
    </div>
  </body>
</html>

6.项目目录下增加node-server.js

node启动服务主文件

// node-server.js
const Koa = require('koa')
const app = new Koa()
const path = require('path')
const fs = require('fs')
const Router = require('koa-router')
const send = require('koa-send')
const router = new Router()
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('./index.ssr.html', 'utf-8'),
  clientManifest
})

function renderToString(context) {
  return new Promise((resolve, reject) => {
    renderer.renderToString(context, (err, html) => {
      err ? reject(err) : resolve(html);
    });
  });
}
router.get('*', async (ctx, next) => {
  const url = ctx.path;
  if(url.includes('.')){
    return await send(ctx, url, {root: path.resolve(__dirname,'./dist/client')});
  }
  const context = {
    url: url
  }
  ctx.res.setHeader("Content-Type", "text/html");
  // 将 context 数据渲染为 HTML
  const html = await renderToString(context);
  ctx.body = html;
})

app.use(router.routes()).use(router.allowedMethods())

app.listen(8001,()=>{
  console.log('服务启动成功')
})

7.修改package.json文件

  "scripts": {
    "serve": "cross-env RUN_ENV=client vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "start": "npm run build:server && npm run build:client && npm run service",
    "build:client": "cross-env RUN_ENV=client vue-cli-service build",
    "build:server": "cross-env RUN_ENV=server vue-cli-service build --mode server",
    "service": "node server.js"
  },

4.打包并运行服务

npm start

三、运行效果图

1.开启ssr的效果

在这里插入图片描述
在这里插入图片描述

2.没有开启ssr的效果

在这里插入图片描述
在这里插入图片描述

四、总结

大致上较为简单的ssr操作就到这里了,如过还需要进一步优化的话,就进行gzip进行压缩,访问起来更快。

gitee 例子 le-vue-ssr-demo

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值