Describes how to use Vue2 for server rendering and vue2 for server
After a month, the vue2 server rendering (SSR) was successfully deployed in the home of the new car, and Vuex was used to manage the status, the loading time of the first screen has increased from 1000 ms in the previous 4G network to-ms. There are many advantages of SSR. Now let me explain it to you.
Technology Stack
Server: Nodejs (v6.3)
Front-end framework Vue2.1.10
Front-end build tool: webpack2.2 & gulp
Code check: eslint
Source code: es6
Front-end routing: vue-router2.1.0
Status Management: vuex2.1.0
Server Communication: axios
Log Management: log4js
Automated project Deployment Tool: jenkins
Vue2 and server-side rendering (SSR)
Vue2.0 creates a virtual DOM on the server, so it can be rendered on the server in advance, solving the problem that a single page has always existed: SEO and the first loading time is much longer. At the same time, in the real sense, the front and back end share a set of code.
Implementation principle of SSR
The client requests the server to obtain matched components based on the request address. The server calls the matched component and returns Promise (the official preFetch method) to obtain the required data. Finally pass
<script>window.__initial_state=data</script>
Write it into the webpage, and then return the rendered webpage on the server.
Next, the client will replace the _ initial_state _ written by vuex with the current global status tree, and then use this status tree to check whether the data rendered by the server is correct. When a component is not rendered by the server, send an asynchronous request to obtain the data. To put it bluntly, it is a React-like shouldComponentUpdate Diff operation.
Vue2 uses a unidirectional data stream. With this data stream, you can use SSR to return a unique global state and check whether a component has passed SSR.
Enable server rendering (SSR)
Currently, we use express as the Web framework. We have used koa for SSR once before. The results show that there are many pitfalls, there are too few cases, and some pitfalls are not well solved, therefore, we chose express for the stability of online projects.
SSR Flowchart
Install SSR
Copy codeThe Code is as follows:
Npm install -- save express vue-server-renderer lru-cache es6-promise serialize-javascript vue-router axios
After vue is updated to 2.0, the author declares that vue-resource is no longer updated and vue-resource does not support SSR. Therefore, I recommend using axios, which can be used on both the server and client.
Vue2 uses virtual DOM, so the browser environment and server environment should be rendered separately. Two corresponding portal files should be created.
Browser entry file client-entry.js
Mount directly with $ mount
Server entry file server-entry
Use vue's SSR function to directly render virtual DOM into a webpage
Client-entry.js files
import 'es6-promise/auto';import { app, store } from './app';store.replaceState(window.__INITIAL_STATE__);app.$mount('#app');
The app. js to determine if the status has been written during rendering on the server, replace the vuex status so that the html rendered on the server and the data managed by vuex are synchronized. Then mount the vue instance to the node specified by html.
Server-entry file
import { app, router, store } from './app';const isDev = process.env.NODE_ENV !== 'production'; export default context => { const s = isDev && Date.now(); router.push(context.url); const matchedComponents = router.getMatchedComponents(); if (!matchedComponents.length) { return Promise.reject({ code: '404' }); } return Promise.all(matchedComponents.map(component => { if (component.preFetch) { return component.preFetch(store); } })).then(() => { return app; });};
In the server-entry file, the server will pass a context object containing the url requested by the current user. vue-router will jump to the url of the current request and pass the router. getMatchedComponents () to obtain the current matched component, call the preFetch hook in the currently matched component, and pass the store (status under Vuex) to return a Promise object, in the then method, assign the existing vuex state to the context to render the server, return the vue instance, and render the virtual DOM into a webpage. The server also generates the initial vuex status to the page. If the vue-router does not match the request url, the system directly returns the reject method in Promise and passes in 404. At this time, the error event of renderStream is displayed below to display the error message on the page.
// Process all get requests app. get ('*', (req, res) =>{// wait for compilation if (! Renderer) {return res. end ('Waiting for compilation... refresh in a moment. ');} var s = Date. now (); const context = {url: req. url}; // render our Vue instance as stream const renderStream = renderer. renderToStream (context); // renderStream when the block is rendered for the first time. once ('data', () =>{// write the pre-HTML into the response res. write (indexHTML. head) ;}); // each time a new block is rendered renderStream. on ('data', chunk => {// write the block to the response res. write (chunk) ;}); // when all the blocks are rendered, renderStream. on ('end', () => {// when the initial status of vuex exists if (context. initialState) {// write the initial vuex state to the page in script Mode res. write ('<script> window. _ INITIAL_STATE __=$ {serialize (context. initialState, {isJSON: true})} </script> ');} // write the ending HTML into the response res. end (indexHTML. tail) ;}); // error renderStream when rendering occurs. on ('error', err =>{ if (err & err. code = '000000') {res. status (404 ). end ('2014 | Page Not Found '); return;} res. status (500 ). end ('internal Error 500 ');});})
The above is the server Rendering Method of vue2.0. Streaming rendering is used to generate HTML while writing it to the corresponding stream, rather than writing it all at the last time. This effect means that the page rendering speed will be very fast. You can also introduce the lru-cache module to cache data and set the cache time. I usually set the cache time to 15 minutes.
You can refer to the vue ssr official demonstration project server implementation https://github.com/vuejs/vue-hackernews-2.0/blob/master/server.js
Use of axios on the client and server
Create two files for communication between the client and the server
Create-api-client.js files (for clients)
Const axios = require ('axios '); let api; axios. defaults. timeout = 10000; axios. interceptors. response. use (res) => {if (res. status> = 200 & res. status <300) {return res;} return Promise. reject (res) ;}, (error) =>{// return Promise due to a network exception. reject ({message: 'network exception, Please refresh and retry ', err: error}) ;}); if (process. _ API _) {api = process. _ API __;} else {api = {get: function (target, params ={}) {const suffix = Ob Ject. keys (params ). map (name => {return '$ {name} =$ {JSON. stringify (params [name])} ';}). join ('&'); const urls = '$ {target }? $ {Suffix} '; return new Promise (resolve, reject) =>{ axios. get (urls, params ). then (res => {resolve (res. data );}). catch (error) =>{ reject (error) ;}) ;}, post: function (target, options ={}) {return new Promise (resolve, reject) => {axios. post (target, options ). then (res => {resolve (res. data );}). catch (error) =>{ reject (error) ;}) ;}};} module. exports = api;
Create-api-server.js files (for servers)
Const isProd = process. env. NODE_ENV = 'production '; const axios = require ('axios'); let host = isProd? 'Http: // yczj.api.autohome.com.cn ': 'http: // t.yczj.api.autohome.com.cn'; let cook = process. _ COOKIE _ | ''; let api; axios. defaults. baseURL = host; axios. defaults. timeout = 10000; axios. interceptors. response. use (res) => {if (res. status> = 200 & res. status <300) {return res;} return Promise. reject (res) ;}, (error) =>{// return Promise due to a network exception. reject ({message: 'network exception, Please refresh and retry ', err: error, type: 1}) ;}; if (process. _ API _) {api = process. _ API __;} else {api = {get: function (target, options = {}) {return new Promise (resolve, reject) =>{ axios. request ({url: target, method: 'get', headers: {'cooker': cook}, params: options }). then (res => {resolve (res. data );}). catch (error) =>{ reject (error) ;}) ;}, post: function (target, options ={}) {return new Promise (resolve, reject) => {axios. request ({url: target, method: 'post', headers: {'cooker': cook}, params: options }). then (res => {resolve (res. data );}). catch (error) =>{ reject (error) ;}) ;}};} module. exports = api;
Because the interface does not actively carry cookies on the server, you need to write cookies in headers. Because interface data changes frequently, no cache is performed.
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.