What is SSR? How to implement SSR server-side rendering in vue?
What is SSR? The following article will introduce to you how to implement SSR server-side rendering in vue. I hope it will be helpful to you!
1. What is SSR
Server-Side Rendering
We call it SSR
, meaning server-side rendering
refers to the page processing technology that completes the HTML
structure splicing of the page on the server side, sends it to the browser, and then binds status and events to it. The process of becoming a fully interactive page. [Related recommendations: vuejs video tutorial]
Let’s first take a look at the development history of Web
in three stages:
- Traditional server Rendering SSR
- Single page application SPA
- Server-side rendering SSR
Traditional web development
Web page content is served End-side rendering is completed and transferred to the browser in one go
Open the page to view the source code. What the browser gets is the entire dom
structure
Single Page Application SPA
The excellent user experience of single page applications has gradually made it become mainstream. The page content is rendered by JS
. This method is called Render for the client
#Open the page to view the source code, the browser only gets the host element#app
, and no content
Server-side rendering SSR
SSR
Solution, the backend renders the complete first screen dom
structure return, the front end gets it The content includes the first screen and the complete spa
structure. After the application is activated, it will still run in the spa
way
After reading the front-end development, we Let’s take a look at Vue
’s official explanation of SSR
:
Vue.js is a framework for building client applications. By default, Vue components can be output in the browser to generate DOM and manipulate DOM. However, it is also possible to render the same components as server-side HTML strings, send them directly to the browser, and finally "activate" these static tags into a fully interactive application on the client
Server Rendering Vue.js applications can also be considered "isomorphic" or "universal" because most of the application's code can run on both the server and the client
We get it from Home Explained The following conclusions:
-
Vue SSR
is an improved server-side rendering onSPA
Vue SSR - The rendered page needs to be activated on the client to achieve interaction
- will contain two parts: the first screen rendered by the server, and the interactive
SPA
SSR mainly solves the following two problems:
seo: search engine priority crawling Take the page- HTML
- structure and use
ssr
, the server has already generated theHTML
associated with the business, which is beneficial toseo
First screen rendering: Users can see the page view without waiting for all
js - of the page to be loaded (the pressure comes to the server, so it is necessary to weigh which should be rendered on the server side and which should be left to the client)
also has the following shortcomings:
- Complexity: the complexity of the entire project
- Performance issues
-
Each request is
- n
- instances Creation, otherwise it will be polluted and the consumption will become very large
cache
node serve - ,
ngin
x determine whether the current user has expired, and cache it if it has not expired , use the result just now.Downgrade: Monitor
cpu - , if the memory usage is too much,
spa
, return a single shell
The server load increases. Compared with the front-end and back-end separated servers that only need to provide static resources, the server load is greater, so we must use it carefully - instances Creation, otherwise it will be polluted and the consumption will become very large
- So when we choose whether to use
, we need to carefully ask ourselves these questions:
- Are there only a few pages that require
- SEO
, and can these use pre-rendering ( How Implementation
For isomorphic development, we still use webpack - for packaging. We have to solve two problems: server-side first screen rendering and client-side activation
Here you need to generate a server
bundle
file for server first screen rendering and a clientbundle
file for client activationExcept for two different entrances, the code structure is exactly the same as the previous
vue
application1
2
3
4
5
6
7
8
src
├── router
├────── index.js # 路由声明
├── store
├────── index.js # 全局状态
├── main.js # ⽤于创建vue实例
├── entry-client.js # 客户端⼊⼝,⽤于静态内容“激活”
└── entry-server.js # 服务端⼊⼝,⽤于⾸屏内容渲染
Copy after loginRouting configuration
1
2
3
4
5
6
7
8
9
10
11
12
import Vue from
"vue"
; import Router from
"vue-router"
; Vue.
use
(Router);
//导出⼯⼚函数
export
function
createRouter(){
return
new
Router({
mode: 'history',
routes: [
// 客户端没有编译器,这⾥要写成渲染函数
{ path:
"/"
, component: { render: h => h('div', 'index page') } },
{ path:
"/detail"
, component: { render: h => h('div', 'detail page') }}
]
});
}
Copy after loginMain file main.js
Different from before, the main file is the factory responsible for creating
vue
instances. Each request will have an independentvue
instance created1
2
3
4
5
6
7
8
9
10
import Vue from
"vue"
;
import App from
"./App.vue"
;
import { createRouter } from
"./router"
;
// 导出Vue实例⼯⼚函数,为每次请求创建独⽴实例
// 上下⽂⽤于给vue实例传递参数
export
function
createApp(context) {
const
router = createRouter();
const
app =
new
Vue({ router, context, render: h => h(App) });
return
{ app, router };
}
Copy after loginWrite the server entry
src/entry-server.js
Its task is to create a
Vue
instance and specify the first screen based on the incomingurl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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(() => {
resolve(app);
}, reject);
});
};
Copy after loginWriting the client entry
entry-client.js
The client entry only needs to create the
vue
instance and perform mounting. This step Called activation1
2
3
4
5
import { createApp } from
"./main"
;
// 创建vue、router实例
const
{ app, router } = createApp();
// 路由就绪,执⾏挂载
router.onReady(() => { app.
$mount
(
"#app"
); });
Copy after loginConfigure
webpack
Install dependencies
npm install webpack-node-externals lodash.merge -D
Configure
vue.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 两个插件分别负责打包客户端和服务端
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 指向应⽤程序的 server / client ⽂件
entry: `./src/entry-${target}.js`,
// 对 bundle renderer 提供 source map ⽀持
devtool: 'source-map',
// target设置为node使webpack以Node适⽤的⽅式处理动态导⼊,
// 并且还会在编译Vue组件时告知`vue-loader`输出⾯向服务器代码。
target: TARGET_NODE ?
"node"
:
"web"
,
// 是否模拟node全局变量
node: TARGET_NODE ? undefined : false,
output: {
// 此处使⽤Node⻛格导出模块
libraryTarget: TARGET_NODE ?
"commonjs2"
: undefined
},
// https://webpack.js.org/configuration/externals/#function
// https://github.com/liady/webpack-node-externals
// 外置化应⽤程序依赖模块。可以使服务器构建速度更快,并⽣成较⼩的打包⽂件。
externals: TARGET_NODE
? nodeExternals({
// 不要外置化webpack需要处理的依赖模块。
// 可以在这⾥添加更多的⽂件类型。例如,未处理 *.vue 原始⽂件,
// 还应该将修改`global`(例如polyfill)的依赖模块列⼊⽩名单
whitelist: [/\.css$/]
})
: undefined,
optimization: {
splitChunks: undefined
},
// 这是将服务器的整个输出构建为单个 JSON ⽂件的插件。
// 服务端默认⽂件名为 `vue-ssr-server-bundle.json`
// 客户端默认⽂件名为 `vue-ssr-client-manifest.json`。
plugins: [TARGET_NODE ?
new
VueSSRServerPlugin() :
new
VueSSRClientPlugin()]
}),
chainWebpack: config => {
// cli4项⽬添加
if
(TARGET_NODE) {
config.optimization.
delete
('splitChunks')
}
config.module
.rule(
"vue"
)
.
use
(
"vue-loader"
)
.tap(options => {
merge(options, {
optimizeSSR: false
});
});
}
};
Copy after loginConfigure the script and install dependencies
npm i cross-env - D
1
2
3
4
5
"scripts"
: {
"build:client"
:
"vue-cli-service build"
,
"build:server"
:
"cross-env WEBPACK_TARGET=node vue-cli-service build"
,
"build"
:
"npm run build:server && npm run build:client"
}
Copy after loginExecute packaging:
npm run build
Last modification of the host file
/public/index.html
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset=
"utf-8"
>
<meta http-equiv=
"X-UA-Compatible"
content=
"IE=edge"
>
<meta name=
"viewport"
content=
"width=device-width,initial-scale=1.0"
>
<title>Document</title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
Copy after loginis the server-side rendering entry location. Be careful not to add spaces before and after it for the sake of appearance.
Installation
vuex
npm install -S vuex
Create
vuex
Factory function1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue'
import Vuex from 'vuex'
Vue.
use
(Vuex)
export
function
createStore () {
return
new
Vuex.Store({
state: {
count
:108
},
mutations: {
add(state){
state.
count
+= 1;
}
}
})
}
Copy after loginMount in
main.js
filestore
1
2
3
4
5
6
7
8
9
10
import { createStore } from './store'
export
function
createApp (context) {
// 创建实例
const
store = createStore()
const
app =
new
Vue({
store,
// 挂载
render: h => h(App)
})
return
{ app, router, store }
}
Copy after loginServer-side rendering is a "snapshot" of the application. If the application relies on some asynchronous data, then the data needs to be prefetched and parsed before starting rendering
In
store
Perform one-step data acquisition1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export
function
createStore() {
return
new
Vuex.Store({
mutations: {
// 加⼀个初始化
init(state,
count
) {
state.
count
=
count
;
},
},
actions: {
// 加⼀个异步请求count的action
getCount({ commit }) {
return
new
Promise(resolve => {
setTimeout(() => {
commit(
"init"
, Math.random() * 100);
resolve();
}, 1000);
});
},
},
});
}
Copy after loginData prefetch logic in the component
1
2
3
4
5
6
export
default
{
asyncData({ store, route }) {
// 约定预取逻辑编写在预取钩⼦asyncData中
// 触发 action 后,返回 Promise 以便确定请求结果
return
store.dispatch(
"getCount"
);
}
};
Copy after loginServer-side data prefetch,
entry-server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { createApp } from
"./app"
;
export
default
context => {
return
new
Promise((resolve, reject) => {
// 拿出store和router实例
const
{ app, router, store } = createApp(context);
router.push(context.url);
router.onReady(() => {
// 获取匹配的路由组件数组
const
matchedComponents = router.getMatchedComponents();
// 若⽆匹配则抛出异常
if
(!matchedComponents.length) {
return
reject({ code: 404 });
}
// 对所有匹配的路由组件调⽤可能存在的`asyncData()`
Promise.all(
matchedComponents.map(Component => {
if
(Component.asyncData) {
return
Component.asyncData({
store,
route: router.currentRoute,
});
}
}),
)
.then(() => {
// 所有预取钩⼦ resolve 后,
// store 已经填充⼊渲染应⽤所需状态
// 将状态附加到上下⽂,且 `template` 选项⽤于 renderer 时,
// 状态将⾃动序列化为 `window.__INITIAL_STATE__`,并注⼊ HTML
context.state = store.state;
resolve(app);
})
.
catch
(reject);
}, reject);
});
};
Copy after loginBefore the client is mounted to the application,
store
should obtain the status,entry-client.js
1
2
3
4
5
6
7
// 导出store
const
{ app, router, store } = createApp();
// 当使⽤ template 时,context.state 将作为 window.__INITIAL_STATE__ 状态⾃动嵌⼊到最终的 HTML
// 在客户端挂载到应⽤程序之前,store 就应该获取到状态:
if
(window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__);
}
Copy after loginClient data prefetching Processing,
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Vue.mixin({
beforeMount() {
const
{ asyncData } = this.
$options
;
if
(asyncData) {
// 将获取数据操作分配给 promise
// 以便在组件中,我们可以在数据准备就绪后
// 通过运⾏ `this.dataPromise.then(...)` 来执⾏其他任务
this.dataPromise = asyncData({
store: this.
$store
,
route: this.
$route
,
});
}
},
});
Copy after loginModify the server startup file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 获取⽂件路径
const
resolve = dir =>
require
('path').resolve(__dirname, dir)
// 第 1 步:开放dist/client⽬录,关闭默认下载index⻚的选项,不然到不了后⾯路由
app.
use
(express.
static
(resolve('../dist/client'), {index: false}))
// 第 2 步:获得⼀个createBundleRenderer
const
{ createBundleRenderer } =
require
(
"vue-server-renderer"
);
// 第 3 步:服务端打包⽂件地址
const
bundle = resolve(
"../dist/server/vue-ssr-server-bundle.json"
);
// 第 4 步:创建渲染器
const
renderer = createBundleRenderer(bundle, {
runInNewContext: false,
// https://ssr.vuejs.org/zh/api/#runinnewcontext
template:
require
('fs').readFileSync(resolve(
"../public/index.html"
),
"utf8"
),
// 宿主⽂件
clientManifest:
require
(resolve(
"../dist/client/vue-ssr-clientmanifest.json"
))
// 客户端清单
});
app.get('*', async (req,res)=>{
// 设置url和title两个重要参数
const
context = {
title:'ssr test',
url:req.url
}
const
html = await renderer.renderToString(context);
res.send(html)
})
Copy after loginSummary
Use
ssr
There is no singleton mode. Each user request will create a newvue
instanceimplementation
ssr
required Realize server-side first screen rendering and client activation-
Server-side asynchronous data acquisition
asyncData
can be divided into first screen asynchronous acquisition and switching component acquisition- The first screen obtains data asynchronously, which should have been completed during server-side pre-rendering
- The switching component is mixed in through
mixin
, and the data acquisition is completed through thebeforeMount
hook
(Learning video sharing: vuejs tutorial, web front-end)
The above is the detailed content of What is SSR? How to implement SSR server-side rendering in vue?. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Using Bootstrap in Vue.js is divided into five steps: Install Bootstrap. Import Bootstrap in main.js. Use the Bootstrap component directly in the template. Optional: Custom style. Optional: Use plug-ins.

You can add a function to the Vue button by binding the button in the HTML template to a method. Define the method and write function logic in the Vue instance.

The watch option in Vue.js allows developers to listen for changes in specific data. When the data changes, watch triggers a callback function to perform update views or other tasks. Its configuration options include immediate, which specifies whether to execute a callback immediately, and deep, which specifies whether to recursively listen to changes to objects or arrays.

Vue multi-page development is a way to build applications using the Vue.js framework, where the application is divided into separate pages: Code Maintenance: Splitting the application into multiple pages can make the code easier to manage and maintain. Modularity: Each page can be used as a separate module for easy reuse and replacement. Simple routing: Navigation between pages can be managed through simple routing configuration. SEO Optimization: Each page has its own URL, which helps SEO.

There are three ways to refer to JS files in Vue.js: directly specify the path using the <script> tag;; dynamic import using the mounted() lifecycle hook; and importing through the Vuex state management library.

Vue.js has four methods to return to the previous page: $router.go(-1)$router.back() uses <router-link to="/" component window.history.back(), and the method selection depends on the scene.

There are three common methods for Vue.js to traverse arrays and objects: the v-for directive is used to traverse each element and render templates; the v-bind directive can be used with v-for to dynamically set attribute values for each element; and the .map method can convert array elements into new arrays.

There are two ways to jump div elements in Vue: use Vue Router and add router-link component. Add the @click event listener and call this.$router.push() method to jump.
