-
单页应用对SEO不友好,页面信息是从打包后再渲染过去的。服务端渲染使用服务端渲染页面,将结果返回到浏览器。
-
内网速度比外网渲染更快
来自Vue
官方的一张图:
实现过程:
-
实现两个
entry
,因为服务端没有渲染的概念,因此client entry
实现客户端挂载功能,server entry
实现获取到应用信息。 -
使用
webpack
分别打包client entry
为client.bundle.js
和server entry
为server.bundle.js
。 -
服务端获取打包好的
bundle
信息,服务端budnle
负责渲染vue
模板将获取的模板插入到模板文件,客户端Bundle
负责将js
信息插入到模板文件进行事件调用。
目录结构
需要安装的依赖:
webpack
webpack-cli
webpack-merge
vue
@vue/server-render
vue-loader
babel-core
babel-loader@7
html-webpack-plugin
express
实现过程:
1.安装vue
和vue ssr
。vue
版本要和vue-server-renderer
版本一致,否则会提示版本不一致报错。
npm install vue
npm install @vue/server-renderer
2.实现渲文件和通用代码
App.vue
<template>
<div id="app"><div class="demo" @click="handleClick">一段内容</div></div>
</template>
<script>
export default {
methods: {
handleClick() {
console.log(111);
},
},
};
</script>
app.js
//vue3引入vue的方式
import { createApp } from 'vue';
import App from './App.vue';
export function createSsrApp() {
const app = createApp(App);
return { app };
}
3.实现模板文件和编写 client-entry.js
和server-entry.js
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="app"></div>
</body>
</html>
client-entry.js
//客户端实现方式使用$mount进行挂载,获取到vue信息,直接对齐进行挂载
import { createSsrApp } from './app';
const { app } = createSsrApp();
app.mount('#app');
server-entry.js
import { createSsrApp } from './app';//将创建的app信息暴露给服务端
export default () => { const { app } = createSsrApp(); return app;};
4.编写package.json打包命令
"scripts": {
"client": "webpack --config ./build/webpack.client.js",
"server": "webpack --config ./build/webpack.server.js",
"build": "npm run client && npm run server",
"test": "echo \"Error: no test specified\" && exit 1"
},
5.编写webpack.config.js
,区分客户端和服务端,合并配置信息需要使用webpack-merge
npm install webpack-merge --save-dev
webpack.base.js
const path = require('path');
//使用vueloader需要引入vueloaderplugin
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
mode: 'production',
//不配置entry信息,entry信息在不同的配置文件中来加载
//解析js和vue文件,安装vue-loader
resolve: {
extensions: ['.js', '.vue'],
},
//解析vue文件,配置loader
module: {
rules: [
// 使用Vueloader编译vue文件
{
test: /\.vue$/,
loader: 'vue-loader',
},
// 它会应用到普通的 `.js` 文件
// 以及 `.vue` 文件中的 `<script>` 块
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
},
],
},
plugins: [new VueLoaderPlugin()],
};
webpack.client.js
const path = require('path');
const { merge } = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const baseConfig = require('./webpack.base');
module.exports = merge(baseConfig, {
entry: path.resolve(__dirname, '../src/entry-client.js'),
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'client.bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
//指定打包后的html文件
filename: 'index.ssr.html',
//指定模板文件
template: path.resolve(__dirname, '../dist/index.ssr.html'),
excludeChunks: ['server'],
minify: {
removeComments: false,
},
}),
],
});
webpack.server.js
const path = require('path');
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base');
//使用merge合并配置信息
module.exports = merge(baseConfig, {
//指定entry为entry.server.js
entry: path.resolve(__dirname, '../src/entry-server.js'),
output: {
//打包到项目的dist目录下面
path: path.resolve(__dirname, '../dist'),
//指定打包后Bundle的名字
filename: 'server.bundle.js',
//需要打包为commonjs规范的代码,服务端在使用,不支持使用es module的规范
libraryTarget: 'commonjs2',
},
plugins: [],
});
6.打包文件,打包
npm run server
//生成server.bundle.js
npm run client
//生成index.ssr.html和cliet.bundle.js文件
7.使用express
编写服务器createServer.js
npm install express
//引入ssr
const { renderToString, render } = require('@vue/server-renderer');
//创建server
const server = require('express')();
const fs = require('fs');
const path = require('path');
const express = require('express');
// Cannot use import statement outside a module
//node服务端不能使用import语法
//获取模板文件
const indexTemplate = fs.readFileSync(
path.resolve(__dirname, './dist/index.ssr.html'),
'utf-8'
);
//使用sever.bundle.js创建vue app,配置webpack.server.js时如果不指定目标为commonjs会提示报错不支持module语法
const createApp = require('./dist/server.bundle').default;
//使用express.static将dist目录下的文件设置为静态资源,否则打包到index.ssr.html中的文件虽然可以看到已经引入了client.bundle.js,但是并不能够访问。引入成功之后,访问http://localhost:8080/client.bundle.js可以看到打包后的js信息
server.use(express.static(path.join(__dirname, './dist')));
server.get('*', async (req, res) => {
const app = createApp();
//renderToString将获取到的应用信息返回为字符串,使用将<div id="app">替换为新打包的内容信息
const appContent = await renderToString(app);
const html = indexTemplate
.toString()
.replace('<div id="app">', `<div id="app">${appContent}`);
//设置返回的文件格式
res.setHeader('Content-Type', 'text/html');
res.send(html);
});
//启动服务
server.listen(8080);
验证:打开http://localhost:8080 点击一段内容文件,可以发现打印了111
没有将client.bundle.js资源静态化会出现的报错信息:
image-20220526110114189.png
参考1:视频
参考2:vue官方
源码资源->github
网友评论