Book continued , I just mentioned it yesterday SSR Server side rendering related content 《 twenty-five ║ Preliminary study SSR Server rendering
》, It mainly explains the related concepts , And why , A little chestnut yesterday because of the time problem , I didn't spread it out for you , What about today , Let's go on with this SSR Server rendering , And combined with
Client rendering , Let's talk about the relevant content , Of course, it still revolves around the principle , It's not about building projects , I'll talk about the project in the next series , Discussion with the group , And take your advice , I thought about it , I'll talk about the next series
Nuxt.js Related contents ( I feel it is necessary to say this , Now the website SEO It's an important drop ), And then the next series is to build a feature rich Background management system
As an open source project , Small partners with goods in hand come to the group , Let's open source together, ha ha ha .


  At this time, careful partners will find out , The daily brain map is missing , ha-ha , did not , It's at the bottom , I'll see at the end of the article .

One ,Client How does browser side rendering work

To introduce how browser rendering works , Let's run it npm run build Look at our previous projects —— It's the first edition of our personal blog , You should remember 《
  docosa- ║Vue actual combat : Personal blog first edition (axios+router)
<>》, Released files , What exactly are there ,

npm run build
Here we go through Webpack pack , Package our projects , Generate a dist catalog , We can see that there are css+fonts+js folder , One more
index.html Static page , We open this static page , You can see the following :
<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <meta
http-equiv=X-UA-Compatible content="IE=edge"> <meta name=viewport content="
width=device-width,initial-scale=1"> <link rel=icon href=/favicon.ico>
<title>blogvue3</title> <link href=/js/about.143cb27a.js rel=prefetch> <link
href=/css/app.51e9ecbc.css rel=preloadas= style> <link
href=/css/chunk-vendors.5aa02cc7.css rel=preloadas= style> <link
href=/js/app.16d68887.js rel=preloadas=script> <link
href=/js/chunk-vendors.1c001ffe.js rel=preloadas=script> <link
href=/css/chunk-vendors.5aa02cc7.css rel=stylesheet> <link
href=/css/app.51e9ecbc.css rel=stylesheet>// It's all style files , Negligible research </head> <body>
<noscript> <strong>We're sorry but blogvue3 doesn't work properly without
JavaScript enabled. Please enable it tocontinue.</strong> </noscript> <div
id=app />// Page mount portal <script src=/js/chunk-vendors.1c001ffe.js />//vue
Block files used ,vue-cli This is the default configuration of the whole family barrel chunk It's about taking everything from node_modules/ in require(import) All of our dependencies are packaged here
<script src=/js/app.16d68887.js />// This is the core of our project , The main thing is app.vue
Content of , Encapsulates all methods , Including routing and page rendering </body> </html>


Observe the generated files , only one div Mount entrance , There is no redundancy dom element , So how do you render the page ? The answer is js append Splicing , Yes , The ones down there js
Will be responsible innerHTML. and js It is interpreted and executed by the browser , So what , We call it browser rendering , I believe everyone here should understand this principle , And we usually use it jQuery
Writing local asynchronous loads is the same , however , There are several fatal drawbacks :

* js Put in dom ending , If js The file is too large , Then it will inevitably cause page blocking .
* As our business needs increase , Packed js The files are getting bigger and bigger , The white screen of the page is more obvious , The user experience is obviously not good , Especially the front page , How many? , Dozens of components render together , Tianna ! I can't believe it
* Not conducive to SEO
* The client runs in the old JavaScript On the engine


This is the time , We'll think of other ways , For example, we will write a static processing for our home page , In order to cope with the corresponding speed , But this is not a good way , We need to deal with two sets of logic , Based on the above problems , Server side rendering is ready to come out ....

summary : I believe you can understand it when you see it here , How does client rendering work , In fact, it is component-based development , And then through the webpack Packaging tools , Deal with our logic js
, Package as a file , It is then deployed with the front page , In this way, we can say that the data in the DOM It's on display .


Two ,Server How does server rendering work

We saw client browser rendering above , Understand the principle and disadvantages , We need to use server rendering at this time ,SSR , Server Side Render For short , Server rendering .
First, the idea of server rendering has a long history , stay ajax Before the rise , All web Applications are server-side rendering , Server direct return html Text to browser ,
User actions such as submitting a form on the login page , Jump to home page after success , The server needs to return two pages . Such disadvantages are obvious , Increased server consumption , here we are vue times , Although we have passed the
api Returned Json, But it needs to be node The server , It's very performance intensive , Caching and optimization are needed , Equivalent to space for time .

Let's talk about the principle first


You can see from this picture , ours SSR Packaging process changed , When rendering on the client side , We webpack
It's packaged into js Constraint file , Direct to browser , Then get the data rendering DOM,

The Internet explanation is a little shy and hard to understand :ssr There are two entry files ,client.js and server.js, All contain application code ,webpack
Through two entry files, they are packaged for the server server bundle And for the client client bundle.
When the server receives a request from the client , A render is created bundleRenderer, this bundleRenderer Will read the server
bundle file , And execute its code , Then send a generated one html To browser , Wait until the client loads client bundle after , It will be generated with the server DOM
conduct Hydration( Judge this DOM And what you're about to generate DOM Is it the same , If it is the same, the client's vue The instance is mounted to this DOM upper , Otherwise, a warning will be prompted ).

You can see that , We added a step : Before that, we were in the browser , adopt JavaScript Frame to render data , But now we go through the middle of our request node The server , then
node The server helps us generate the corresponding Html fragment , Direct to browser , That browser must be recognition html Of , So you don't have to go through it js
To get the data and render it , Just render it , Well, that's about it , It's like a middleware .

I believe you may not be very clear about the content , The key time still has to go on the code to be able to say more clearly .


Three , Server side rendering through code

Let's not write code for client rendering , I've written a lot these days

1, First we create a new folder Vue_SSR_Demo And to its node Service initialization

npm install vue vue-server-renderer --save
You will see that a node_modules folder and package-lock.json file .

And then execute
npm install express --save
install express Of node service .


2, Then create one index.html page , As a hosting page , Like us vue-cli In scaffolding index.html
<!-- like vue-cli Create the index.html --> <!DOCTYPE html> <html lang="en"> <head>
<meta charset="UTF-8"> <title>{{title}}</title> {{{meta}}} </head> <body>
<!--vue-ssr-outlet--> <!--↑↑↑↑↑ Pay attention to the format above , And no spaces ↑↑↑↑↑--> </body> </html>

3, Create a new one server.js file , As our service portal
const Vue = require('vue')// introduce vue const server = require('express')()// introduce
express Service Framework const fs = require('fs') // read html Template const renderer = require('
vue-server-renderer').createRenderer({ template: fs.readFileSync('./index.html',
'utf-8')// File address path }) // This parameter is vue generate Dom Data from other locations as vue Generated dom Generally located in body In an element container , //
This data can be found in header Label rendering , yes renderer.renderToString() Second parameter of ,// The first parameter is vue example , The third parameter is a callback function .
const context = { title: ' Lao Zhang's Philosophy ', meta:` <meta name="viewport" content="
width=device-width, initial-scale=1" /> <meta name="description" content="
vue-ssr"> <meta name="generator" content="GitBook 3.2.3"> ` } // Defining services server.get(
'*', (req, res) => { // establish vue example It is mainly used for replacement index.html in body Note the content of the place , //index.html in
<!--vue-ssr-outlet--> The place of , established by the people through long social practice const app = new Vue({ data: { url: req.url,
data: ['C#', 'SQL', '.NET', '.NET CORE', 'VUE'], title: ' My skills list ' }, //template
The outermost layer of the text in must be wrapped in a container , and vue Is the same in the components of ,// There can be only one parent element , Here is div! template: ` <div>
<p>{{title}}</p> <p v-for='item in data'>{{item}}</p> </div> ` }) // take Vue
app The instance is rendered as a string ( other API I think the usage is the same ) renderer.renderToString(app, context, (err, html)
=> { if (err) { res.status(500).end('err:' + err) return } // Send template to browser
res.end(html)// Every request It's all there node Print in server console.log('success') }) }) // The service port opens and listens
server.listen(8060, () => { console.log('server success!') })
The explanation in the document is very detailed , You can take a look by yourself , So we define one node service , And passed express frame , Will our vue Instance passed
renderer.renderToString() Method to generate a string , Return to browser .


4, open node service

node server
be careful , there server It's our file name , You can also use other ones , such as node aaa.js, perhaps node aaa



This is the time , We found that we had successfully returned our page content to the browser , Why? ? Because our page source code already has content , The proof was not passed js Post rendered .binggo!

Are you right SSR Server side rendering has a certain amount of any and understanding , Does it feel a little bit , This is still the simplest one node Server rendering .

  The code will not be uploaded , Just paste and copy , All structure documents



Four , adopt webpack pack , To learn more about server rendering

 dang dang
dang, If you see it here, it's easy , Or understand the front , Good drop , You can see this one , If it's not very clear on the top , Or it's hard to understand , ok , This one may be more shy , But it doesn't matter , take your time !

1, This code is from yesterday , Let's talk about it again here

The structure is as follows :
├── dist      // Save our packaged files ├── node_modules   // Dependent package folder ├── entry      //
Package entry folder │ └── entry-server.js // Server Package entry file ├── src      // Our project source code documentation │ ├──
views // view Storage directory │ │ ├── about.vue      //about page │ │ ├── like.vue       
//like page │ │ └── Home.vue     //Home page │ └── App.vue        // App Entry file │ └──
main.js         // Master profile │ └── router.js       // Routing profile └── .babelrc // babel
configuration file └── package.json // Project dependency package profile └── package-lock.json // npm5 New documents , optimize performance └──
server.js // server file └── // Documentation

  Let's talk about it separately

2, ordinary app Code block

This one , It's our counterpart src Templates under folder , We must be familiar with these contents , I won't say much , namely Definition of components , Route definition ,app Entrance and main.js
Main method , Here's the point main.js

Before main.js We are instantiating directly vue() , And then yes #appp For mounting , But now we are
Server rendering , You can't mount it here , It's about creating vue The instance returns .
//main.js import Vue from 'vue' import createRouter from './router' import App
from './App.vue' // Export a factory function , Used to create a new vue example export function createApp() { const
router = createRouter() const app = new Vue({ router, render: h => h(App) })
return app }
You'll ask , But to whom , A kind of ?! That's a good question , Please look down .

3, Talk about us vue Instance encapsulation to promise


Summary of netizens : so-called Promise, In short, it's a container , There is an event that will end in the future ( It's usually an asynchronous operation ) The results of . Grammatically ,Promise
It's an object , From it you can get messages for asynchronous operations .Promise Provide unified API, All kinds of asynchronous operations can be handled in the same way .

Promise The object has the following two characteristics .
(1) The state of the object is not affected by the outside world .Promise Object represents an asynchronous operation , There are three states :Pending( have in hand ),Resolved( Completed , also called
Fulfilled) and Rejected( Failed ). Only the result of an asynchronous operation , You can decide which state it is , Nothing else can change this state . This is also true Promise The origin of the name , Its English meaning is “ promise ”, It means that other means cannot be changed .

(2) Once the state changes , It won't change again , This result can be obtained at any time .Promise Object state changes , There are only two possibilities : from Pending Become Resolved And from Pending Become Rejected. As long as these two things happen , The state solidifies , It won't change again , This result will always be maintained . Even if the change has already happened , You're right Promise Object to add a callback function , And you'll get that immediately . This is related to events (Event) totally different , The event was characterized by , If you miss it , Listen again , There is no result .
Yes Promise object , The asynchronous operation can be expressed in the process of synchronous operation , Avoid layer by layer nested callback function . in addition ,Promise Object provides a unified interface , Makes it easier to control asynchronous operations .

  In short , It's about taking us main In the entry file vue example , All packaged into promise, It's like adding a coat , It's convenient for us webpack pack . Yes , Here's the point


4, adopt Webpack Server packaging


/* 5,webpack.server.js Server side packaging */ const path = require('path');// Get path object const
projectRoot = path.resolve(__dirname,'..');// Root path // Defining modules module.exports = { //
Let me know here server bundle use Node Style export module (Node-style exports)//
It has to be here node, Because the running environment of the package is node, stay node End running , Not running on the browser side . target: 'node', //
entry A separate entry file is required entry: ['babel-polyfill', path.join(projectRoot, '
entry/entry-server.js')], // output output: { //
appoint libraryTarget The type of commonjs2, Used to specify the code export Form of entrance .// stay node.js The middle module is module.exports
= {...},commonjs2 The packaged code export form is similar to this . libraryTarget: 'commonjs2', path:
path.join(projectRoot,'dist'), // Packaged path filename: 'bundle.server.js',//
Package the final file name , This document is for node Server used }, module: { // Because of the use of webpack2, It has to be here rules, If used use, //
Will report a mistake :vue this._init is not a function rules: [ // rule 1,vue Rule definition { test: /\.vue$/
, loader:'vue-loader', },//js Rule definition { test: /\.js$/, loader: 'babel-loader',
include: projectRoot,// Here will be the node_modules The things in it are excluded , Improve packaging efficiency exclude: /node_modules/
,// ES6 grammar options: { presets: ['es2015'] } },//css definition { test: /\.less$/,
loader:"style-loader!css-loader!less-loader" } ] }, plugins: [], resolve: {
alias: {'vue$': 'vue/dist/vue.runtime.esm.js' } } }
The basic content is the above , The notes are clear , Everyone can 以看一看,这个时候我们的准备工作就已经做好了,下一步就改打包了


5,执行打包命令,生成服务端约束文件 bundle.server.js
npm run server
这个时候,你会发现,我们的dist 文件夹内,多了一个 bundle.server.js 文件

 我们看一下生成的文件,部分截图,会发现,我们的这个文件包含了所有页面内的内容和方法,但是这个 bundle.server.js
并不是直接返回给前端的,而且在 node 服务器使用的

6,配置 node 服务器启动文件,这个更类似我们上文中提到的 server.js 文件
/*7, server.js */ const express = require('express')()//引入express 服务框架 const
renderer = require('vue-server-renderer').createRenderer() const createApp =
require('./dist/bundle.server.js')['default']//引入我们刚刚打包文件 // 响应路由请求 express.get(
'*', (req, res) => { const context = { url: req.url } // 创建vue实例,传入请求路由信息
createApp(context).then(app => { renderer.renderToString(app, (err, html) => {
if (err) { return res.state(500).end('运行时错误') } res.send(` <!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>Vue2.0 SSR渲染页面</title>
</head> <body> ${html} </body> </html> `) }) }, err => { if(err.code === 404) {
res.status(404).end('所请求的页面不存在') } }) }) // 服务器监听地址 express.listen(8089, () =>
{ console.log('服务器已启动!') })

node server

好啦,这个就是 SSR 服务端渲染的整个过程.



哈喽大家好,在这里忙碌的日子又和大家见面了,咱们的前后端系列入门篇已经 26
API ,Swagger 文档,Sugar 数据持久层的ORM,Repository仓储架构,Asyn/Await
异步编程,AOP面向切面编程,IoC控制反转和DI依赖注入,Dto数据传输对象,Redis缓存等后端知识,还有Vue 基础语法,JS高级,ES6,Vue 组件
,生命周期,数据绑定,开发环境搭建,Vue-Cli 脚手架,axios Http请求,vue-router 路由协议,webpack 打包,Vuex

本来想着要换其他的系列,但是在群里小伙伴的建议下,还是在把Vue好好说说吧,思考了下,在国庆前的时间再说下 SSR 框架——Nuxt.js