The article turns from the melodious little Q, the original address:
http://blog.myweb.kim/vue/%E8%AE%A9vue-cli%E5%88%9D%E5%A7%8B%E5%8C%96%E5%90%8E%E7%9A%84%E9%A1%B9%E7%9B%AE%E9% 9b%86%e6%88%90%e6%94%af%e6%8c%81ssr/?utm_campaign=ligang&utm_source=csdn&utm_medium=blog
The current trend of SPA architecture is at its zenith, but in SEO it seems to have been a pain point, so many popular mv* frameworks have also proposed a solution for this pain point.
Vue has provided the tools VUE-CLI to quickly build the project, and its convenience and quickness are well known. This article is to share a bit about how to integrate SSR (server side render) after building a project using the Vue CLI, this article mainly shows two ways to achieve the effect of SSR.
Two examples of git address: vue-prerender-demo Vue-ssr-demo
This article for the Vue more familiar with the vue-cli have a little understanding of the students. 1. My Environment node v8.5.0 npm v5.0.0 vue-cli v2.8.2 MacOS 10.12.3
The above is not an important factor ~ ~ 2. Mode one: Use the Prerender-spa-plugin plug-in to obtain the effect of SSR. 2.1 Description
Plugin Address: Prerender-spa-plugin
Strictly speaking, this implementation is not called SSR, but a pre rendering. But the effect is the same, and may even be better than SSR in some way. Compared with the official SSR cumbersome configuration, PreRender configuration is simpler and faster, if no special requirements only in the Webpack to add a plugin configuration. However, this method only supports H5 history Routing and does not support hash-style routing.
PreRender is mainly using Phantom JS Simulation browser environment, the specified routing page is placed in Phantom J S, so. Vue works in Phantom and finishes rendering, PreRender then gets the rendered DOM structure and writes it to the corresponding routed HTML file.
After the service starts, enter the corresponding routing address in the real browser environment and the server will return the HTML generated by PreRender to the browser, thus achieving the SSR effect. 2.2 Initialization
Make sure the VUE-CLI installation is successful and execute the command:
Vue init webpack Vue-prerender-demo//This article is configured on a webpack basis
After a carriage return, the build tool prompts you for some of the project information related settings. Here I chose Vue-router, code check Eslint, Standard, did not choose Integration test and Unit test, the installation package is too time-consuming.
Initialization complete:
CD Vue-prerender-demo
npm install
npm Run dev
Enter the project, install it, start the project, and make sure the project is working properly. 2.3 Configuration
To facilitate the test results, I made the following modifications to the initialized demo: Change the route mode to history add a test component, and the Hello component rating, as a separate routing page to modify the configuration in Router/index.js, increase/test routing. Added the <router-link to= "/test" >/test</router-link> to the Hello component, <router-link to= "/" > Back to the first page of the test component </router-link>
So after viewing the page, from the Home->test-> home page Jump between, the route can work properly. 2.4 Start
Then you can start the formal work: 1. Install Prerender-spa-plugin, because rely on phantom Js,phantom installation compare egg pain, too time-consuming ~
NPM Install prerender-spa-plugin-d
2. Start PreRender related configuration:
Modify Webpack.prod.conf.js, only in the production environment for pre-rendering.
Reference to
var prerenderspaplugin = require (' prerender-spa-plugin ')
//...
Plugins: {
//...
.. Configure the
path to the Prerender-spa-plugin new Prerenderspaplugin (
//build file, which is consistent with the Webpack packaged address
Path.join ( Config.build.assetsRoot),//config.build.assetsroot the configuration generated for the Vue CLI, the packaged file address
//configuration to be a pre rendered route, only support H5 history method
[' /', '/test ']
)
//...
}
3. Compile
To run the command:
NPM Run Build
After waiting for the command to complete, you can see the file structure under the Dist directory:
Compared to the original configuration package out of the content of a test directory, this directory corresponding to the PreRender configuration of the/test route, then configured/is dist/index.html it. Right, that's it.
Open dist/index.html? Look at the content, there are many things in this file, is no longer a lonely single <div id= "app" ></DIV> now the DOM structure inside the body is actually rendered in the browser The path page DOM structure is consistent. Test/index.html is the DOM structure that corresponds to accessing the/test rendering. 4. Verify
This step can be ignored. This uses Python as a fast-start server.
To confirm that the final effect is correct in real-world situations, I started an HTTP service locally using Python (without webpack and node as a service)
CD dist//enter into the corresponding directory
python-m simplehttpserver 8888//dist as the root directory, start 8888 port,
Enter localhost:8888/test directly in the browser and right-click to view the Display page source code:
In/test's response content we can see the return is the render DOM structure, the search engine's small spider can obtain the content smoothly, thus achieves the SEO effect. 2.5 Advantages and disadvantages
Excellent
Simple, easy to start, no configuration can meet the basic requirements of the SEO
missing
Supports only H5 history
Not suitable for frequently changing pages if this page wants to do SEO optimization. Because pre-rendering is just a concept similar to snapshot.
Demo address in this way: Vue-prerender-demo 3. Mode two: Use the official provided wheels to do SSR 3.1 Instructions at node end
This example only shows how to complete a relatively basic ssr,vuex and caching, and so on, refer to the official website instructions.
Official Document Address: https://ssr.vuejs.org/zh/
The official document begins with the minimum version requirements for "vue and the library, why the SSR is used, and the Prerender-spa-plugin Plug-ins mentioned above.
And as follows:
This guide will be very in-depth and assume that you are familiar with the vue.js itself and have a fairly good application experience with Node.js and Webpack. If you tend to use a higher level solution that provides a smoother out-of-the-box experience, you should try to use nuxt.js. It builds on the same Vue technology stack, but abstracts many templates and provides additional functionality, such as static site generation. However, if you need to control the structure of the application more directly, Nuxt.js is not suitable for this use scenario.
Official Vue SSR Demo:hackernews Demo
Compared to the PreRender plug-in to contrast, SSR can be used to the complexity of the day to form a bar ~ ~
Follow this section to implement a basic version of SSR configuration. 3.2 Constraints
If you are going to use SSR for your Vue project at node, then in common code, we need to adhere to these conventions as follows:
Generic code: The portion that runs on both the client and server side is common code. Note that the server only calls Beforecreat and created two hooks, so it cannot be done like initializing a timer in created, and then destroying the timer in mounted or destroyed, or the servers will slowly be squeezed by these timers. Because of the single-threaded mechanism, when rendering on the server side, there is a single instance in the process, all requests share the operation of the single instance, so the factory function should be used to ensure the independence of each request. If a Third-party API is used in Beforecreat and created hooks, it is normal and reasonable to ensure that the API does not run incorrectly at the node side, such as initializing a data request in the created hook. However, if only the use of XHR to operate, then the node-side rendering is problematic, so you should take axios this browser-side and server-side support of Third-party libraries. The most important point: do not use document in common code, which can only run on the browser side of the API, in turn, can not use only the node to run the API. 3.3 Preparation Work
To initialize a project again using VUE-CLI:
Vue Init webpack Vue-ssr-demo
And then
CD Vue-ssr-demo
npm install
npm Run dev
Make sure that the initialized project is working properly, and then start to toss it slowly ~ ~ 3.4 begins to toss 1. Install SSR Support First
NPM i-d Vue-server-renderer
The important thing is that Vue-server-renderer and Vue versions must match consistently 2. Increase routing test and page
Random Write a counter, to verify the service side rendering, the Vue mechanism will work properly.
<template>
<div>
Just a test page.
<div>
<router-link to= "/" >Home</router-link>
</div>
<div>
3. Create two JS in the SRC directory:
SRC
├──entry-client.js # runs only in browser
└──entry-server.js # runs only on servers
4. Modify the router configuration.
No matter what system routing is always the most important, server-side rendering naturally has to be common to the system, and in order to avoid the effects of a single example, here only a new router instance is exported for each request:
Import Vue from ' Vue '
import Router from ' vue-router '
import HelloWorld ' @/components/helloworld
' Vue.use (Router)
export function Createrouter () {return
new Router ({
mode: ' History '),//Note that this is also the history mode C7/>routes: [
{
path: '/',
Name: ' Hello ',
component:helloworld
}, {
path: '/test ',
name: ' Test ',
Component: () => import (' @/components/test ')//Asynchronous Component
}
}
)
}
5. Transformation of Main.js
Main.js initialization is only suitable for the browser to run, so to transform both sides can use the file, also in order to avoid a single example of the impact, here will be exported a Createapp factory function:
Import Vue from ' Vue ' to ' import App from '
./app '
import {createrouter} from './router '
export function createap P () {
///Create router instance
Const Router = new Createrouter ()
const APP = new Vue ({
//inject router to root Vue instance
Router,
render:h => H (APP)
})
//back to app and router return
{app, router}
}
6. Entry-client.js adds the following content:
Import {Createapp} from './main '
const {app, Router} = Createapp ()
//Because asynchronous components may exist, wait for router to load all asynchronous components, server-side with This operation is also required
router.onready (() => {
app. $mount (' #app ')
})
7. Entry-server.js
Entry-server.js
Import {Createapp} from './main '
Export default context => {
//Because there may be an asynchronous route hook function or component, so We will return a Promise,//
so that the server can wait for all content to be rendered before the//
is ready. return
New Promise ((Resolve, Reject) => {
const {app, Router} = Createapp ()
//Set server-side router location
Rou Ter.push (Context.url)
//wait until router resolves the possible asynchronous components and hook functions
router.onready (() => {
const matchedcomponents = Router.getmatchedcomponents ()
///unmatched route, executes reject function, and returns 404
if (!matchedcomponents.length) {
// Eslint-disable-next-line return
reject ({code:404})
}
//Promise should resolve the application instance so that it can render
Resolve (APP)
}, Reject)}}
8. Webpack Configuration
Vue the related code has been processed, then the Webpack package configuration needs to be modified.
The website recommends the following configuration:
build ├──webpack.base.conf.js # Basic Generic Configuration
├──webpack.client.conf.js # Client packaged configuration
└── Webpack.server.conf.js # Server-side packaged configuration
However, there are three VUE-CLI initialization configuration files: base, Dev, prod, we still retain these three profiles, only need to add webpack.server.conf.js. 9. Configuration of Webpack clients
Modify the Webpack.base.conf.js entry Portal configuration to:./src/entry-client.js. Neither the original dev configuration nor the prod configuration will be affected.
The server-side configuration also references the base configuration, but overwrites the entry through the merge to Server-entry.js.
Build client build List clients manifest
Benefits: When there is a hash in the generated file name, you can replace html-webpack-plugin to inject the correct resource URL. When rendering bundle through the Webpack on-demand Code segmentation feature, we ensure that chunk is optimized for resource preload/data prefetching, and that the required asynchronous chunk can be intelligently injected into <script> tags to avoid cascading requests from clients ( Waterfall request), and to improve the interactive time (tti-time-to-interactive).
In fact, it is very simple to introduce a plug-in into the PROD configuration and configure it to plugin:
Const Vuessrclientplugin = require (' vue-server-renderer/client-plugin ')///... plugins: [New W Ebpack.
Defineplugin ({' process.env ': env, ' Process.env.VUE_ENV ': ' Client ' '//Add Process.env.VUE_ENV} '),
...//In addition, we need to remove the prod htmlwebpackplugin, because after we have Vue-ssr-client-manifest.json, the server side will help us do the work. New Htmlwebpackplugin ({//Filename:config.build.index,//Template: ' index.html ',//INJEC T:true,//minify: {//Removecomments:true,//Collapsewhitespace:true,//R Emoveattributequotes:true///More options:////Https://github.com/kangax/html-minifier#options
-quick-reference//},////necessary to consistently work with multiple via chunks
Chunkssortmode: ' Dependency '//},//This plugin generates ' Vue-ssr-client-manifest.json ' in the output directory//. New VuessrclientPlugin ()]///...
Webpack server-side configuration
The configuration of the server is useful for new Plug-ins to run the installation: NPM i-d webpack-node-externals
The Webpack.server.conf.js configuration is as follows:
Const WEBPACK = require (' webpack ') const merge = require (' webpack-merge ') const NODEEXTERNALS = require (' Webpack-nod E-externals ') const BASECONFIG = require ('./webpack.base.conf.js ') const Vuessrserverplugin = require (' Vue-server-rend
Erer/server-plugin ')//removal of package CSS configuration baseconfig.module.rules[1].options = ' Module.exports = Merge (Baseconfig, { Point entry to the application's server entry file entry: './src/entry-server.js ',//This allows Webpack to be used by Node (Node-appropriate FA
Shion) Handles dynamic import,//And, when compiling the Vue component,//tells ' Vue-loader ' to deliver server-oriented code (server-oriented codes). Target: ' node ',//provide source map support to bundle renderer Devtool: ' Source-map ',//here Tell server bundle to use node style guide Out module (Node-style exports) output: {librarytarget: ' commonjs2 '},//https://webpack.js.org/configuration/ externals/#function//https://github.com/liady/webpack-node-externals//External application dependencies module.
You can make your server build faster,//and generate smaller bundle files. Externals:nodeexTernals ({//) do not externally webpack dependent modules that need to be processed. You can add more file types here.
For example, the *.vue original file was not processed,//You should also include a dependency module for modifying ' Global ' (such as Polyfill) on the whitelist Whitelist:/\.css$/}), plugins: [ New Webpack. Defineplugin ({' Process.env.NODE_ENV ': json.stringify) (Process.env.NODE_ENV | |
' Development '), ' Process.env.VUE_ENV ': ' ' server '},//This is a plug-in that will complete the server's output//build as a single JSON file. The default file name is ' Vue-ssr-server-bundle.json ' new Vuessrserverplugin ()]})
Note that a property is removed from the Baseconfig
Baseconfig.module.rules[1].options = '//remove separate CSS packaged plugins
11. Configure Package.json Add Package server-side Build command and modify original Package command
"Scripts": {
///...
" Build:client ": Node Build/build.js",
"Build:server": "Cross-env node_env=production webpack--config build/ Webpack.server.conf.js--progress--hide-modules ", Build
": "Rimraf Dist && npm run build:client && NPM run Build:server "
}
If cross-env cannot be found, please install NPM i-d cross-env 12. Modify Index.html
<! DOCTYPE html>
The original <div id= "app" > deleted, only keep a mark in the body:<!--vue-ssr-outlet-->. The server side will automatically generate a <div id= "app" data-server-rendered= "true" in the location of this tag, and the client will mount to the service-side generated elements via the app. $mount (' #app ') and become responsive.
Note that template HTML is modified here to the service side rendering applicable template, but the dev mode in the project also applies to this template, but will be unable to find #app to the error, you can do this: the simplest way, for the dev mode to create a separate HTML template ... It also integrates the service-side rendering mode for the dev pattern, which is quite plausible regardless of whether the production environment and the development environment are in the service-side rendering mode together. (This is the official example of this operation) 13. Run Build Command
NPM Run Build
The resulting two JSON files are then visible in the Dist directory: Vue-ssr-server-bundle.json and Vue-ssr-client-manifest.json.
These two files will be applied to the node side for server-side rendering and injection of static resource files. 14. Build the server side (the official example uses Express, so this demo will use KOA2 as the server side, of course, both KOA and express are not important ...)
NPM I-s KOA
The server.js is created in the project root directory, as follows
Const KOA = require (' Koa ')
const APP = new Koa ()
//Response
App.use (ctx => {
ctx.body = ' Hello Koa '
})
App.listen (3001)
Run node server.js, Access localhost:3001, and make sure the browser gets Hello Koa. 15. Writing service-side code
Need to install KOA static resource middleware: NPM i-d koa-static
The Server.js code is as follows:
Const KOA = require (' Koa ') const APP = new Koa () const FS = require (' FS ') const PATH = require (' path ') const {Createbundl Erenderer} = require (' vue-server-renderer ') const resolve = File => path.resolve (__dirname, file)//Generate service-side render function const Renderer = Createbundlerenderer (Require ('./dist/vue-ssr-server-bundle.json '), {//Recommended runinnewcontext:false,//template HTML file Template:fs.readFileSync (Resolve ('./index.html '), ' utf-8 '),//Client Manifest Clientmanifest:require ('./di
St/vue-ssr-client-manifest.json ')}) function rendertostring {return new Promise (Resolve, reject) => { Renderer.rendertostring (context, (err, HTML) => {Err. Reject (ERR): Resolve (HTML)})} App.use (requ IRE (' koa-static ') (Resolve ('./dist '))//Response App.use (Async (CTX, next) => {try {const context = {Ti XT)//Set Request Head CTX.set (' Content-type ', ' text/html ') ctx.set (' Server ', ' KOA2 server Side Render ')} catch (e) {//If not found, let go of the request, continue to run Later middleware Next ()}) App.listen (3001)
To run the start service command:
Node Server.js
16. Done
Browser access: Localhost:3001/test, screenshot for the server to render a successful page