一、问题
当我们平时开发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'
export default context => {
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
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: `./src/${env.RUN_ENV}.js`,
devtool: 'eval',
target: isServer ? 'node' : 'web',
output: {
libraryTarget: isServer ? 'commonjs2' : undefined
},
externals: isServer ? nodeExternals({
allowlist: /\.css$/
}) : undefined,
optimization:{splitChunks:isServer ? false : undefined},
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启动服务主文件
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");
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
|