Vuecli project builds SSR server rendering

Vuecli project builds SSR server rendering

Server-side rendering (SSR)

The process of rendering a Vue component into an HTML string on the server side and sending it to the browser, and finally "activating" these static tags as an interactive application is called server-side rendering (SSR)
server-rendered Vue.js application. Can be considered "isomorphic" or "universal" because most of the code of the application can be run on the server and the client

Why use server-side rendering (SSR)

  • Better SEO: Traditional spa page data is loaded asynchronously, search engine crawlers cannot crawl, server-side rendering (SSR) allows search engine crawlers to directly view the fully rendered page, solving the seo problem of the vue project
  • Faster content arrival time ( 首屏加载更快): When requesting a page, the server sends the rendered page directly to the browser for rendering. The browser only needs to parse and render HTML, without waiting for all JavaScript to be downloaded and executed before displaying the server Rendered marker

Server-side rendering (SSR) disadvantages

  • Development conditions are limited: browser-specific code can only be used in certain life cycle hook functions; some external extension libraries may require special processing to run in server rendering applications
  • More requirements related to build setup and deployment: Unlike a fully static single page application (SPA) that can be deployed on any static file server, the server rendering application needs to be in the Node.js server runtime environment
  • More server-side load: Rendering a complete application in Node.js will obviously consume more CPU resources than a server that only provides static files. Therefore, if you expect to use it in a high-traffic environment, you need to prepare a corresponding server load. And adopt a caching strategy

Server-side rendering (SSR) vs. prerendering (Prerendering)

If you just want to improve the SEO of a few marketing pages (such as /, /about, /contact, etc.), then you may need pre-rendering instead of dynamically compiling HTML in real-time with a web server. Instead, use pre-rendering, which is simply Generate static HTML files for specific routes. The advantage is that it is easier to set up pre-rendering, and you can use your front end as a completely static site.
If you use webpack, you can easily add pre-rendering using the prerender-spa-plugin (npm address) plugin

Server-side rendering (SSR) principle

Build process: All files have a common entrance app.js, entrance into the server entry-server.jsand client-side entrance entry-client.js, after completion of the project by using webpack package generated server server bundle(a server for SSR json file used) and a client client bundle(a browser) When the page is requested, the server assembles the vue component into an HTML string and sends it to the browser, mixed into the HTML template accessed by the client, to complete the page rendering
Insert picture description here

Create a vue project through vuecli

vue create vue-ssr-demo

vue-server-renderer

vue-server-rendererSSR is a rendering of the core, providing createRenderera method, this method renderToStringcan be rendered into a string app. createBundleRendererMethods can create bundleRenderer instances through pre-packaged application code to render bundles and HTML templates

Install vue-server-renderer

npm install vue-server-renderer --save

note:

  • vue-server-renderer and vue must match the version
  • vue-server-renderer relies on some Node.js native modules, so it can only be used in Node.js

Avoid state singleton

The Node.js server is a long-running process. When our code enters the process, it will take a value and store it in the memory. This means that if a singleton object is created, it will be Shared between requests, so we should expose a factory function that can be executed repeatedly and create a new root Vue instance for each request. If we use a shared instance between multiple requests, it is easy to cause cross-request state pollution (The same rules apply to router, store and event bus instances)

Create routing router

Install vue-router

npm install vue-router --save

In srcthe directory to create routera folder and index.js
create Home.vue and About.vue page in the components directory (custom-created based on project requirements)

router/index.js:
import Vue from "vue"
import Router from "vue-router"

import Home from "@/components/Home"
import About from "@/components/About"

Vue.use(Router)

//每次用户请求都需要创建一个新的router实例
//创建createRouter工厂函数
export default function createRouter() {
    
    
    //创建router实例
    return new Router({
    
    
        mode: "history",
        routes: [
            {
    
    
                path: "/", 
                name: 'home',
                component: Home
            },
            {
    
    
                path: "/about", 
                name: 'about',
                component: About
            }
        ]
    })
}

Modify App.vue

Modify the App.vue page for page layout (customize the layout according to project requirements)

App.view :
<template>
  <div id="app">
    <nav>
      <router-link to="/">首页</router-link>
      <router-link to="/about">关于</router-link>
    </nav>
    <router-view></router-view>
  </div>
</template>

Create a public entrance app.js

In the srccreation of public directory entry app.js, for instance to create vue

app.js:
import Vue from "vue"
import App from "./App.vue"
import createRouter from "./router"

//创建createApp工厂函数
export default function createApp() {
    
    
    const router = createRouter()
    //创建vue实例
    const app = new Vue({
    
    
        router,
        render: h => h(App),
    })
    return {
    
     app, router }
}

Create server entry entry-server.js

In srccreating a service entrance at the end directory entry-server.js, for rendering first screen

entry-server.js:
import createApp from "./app"

export default context => {
    
    
    return new Promise((resolve, reject) => {
    
    
        const {
    
     app, router } = createApp()
        //渲染首屏
        router.push(context.url)
        router.onReady(() => {
    
    
            resolve(app)
        }, reject)
    })
}

Create a client portal entry-client.js

In srccreating a client entry in the directory entry-client.jsfor the mount activate app

entry-client.js:
import createApp from "./app"

const {
    
     app, router } = createApp()
router.onReady(() => {
    
    
    //挂载激活app
    app.$mount("#app")
})

Create page template index.temp.html

In the publicdirectory is created index.temp.html, as the Vue rendering application, renderer generates HTML pages wrapped container, to wrap the generated HTML markup
<!--vue-ssr-outlet-->comments will be applications where injected HTML tags

index.temp.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue ssr</title>
</head>
<body>
    <!--vue-ssr-outlet-->
</body>
</html>

Create Node.js server

Server-side rendering (SSR) requires Node.js server, where the use expressframework to build
install express

npm install express --save

Create a root directory server.jsfile used to build Node.js server

server.js:
//nodejs服务器
const express = require("express")
const Vue = require("vue")
const fs = require("fs")

//创建express实例
const app = express()
//创建渲染器
const {
    
     createBundleRenderer } = require("vue-server-renderer")
const serverBundle = require("./dist/server/vue-ssr-server-bundle.json")
const clientManifest = require("./dist/client/vue-ssr-client-manifest.json")
const renderer = createBundleRenderer(serverBundle, {
    
    
    runInNewContext: false,
    template: fs.readFileSync("./public/index.temp.html", "utf-8"), //页面模板
    clientManifest
})

//中间件处理静态文件请求
app.use(express.static("./dist/client", {
    
    index: false}))

//将路由的处理交给vue
app.get("*", async (req, res) => {
    
    
    try {
    
    
        const context = {
    
    
            url: req.url,
            title: ""
        }
        const html = await renderer.renderToString(context)
        res.send(html)
    }catch {
    
    
        res.status(500).send("服务器内部错误!")
    }
})

app.listen(9999, () => {
    
    
    console.log("服务器渲染成功!")
})

webpack packaging configuration

Vue create the configuration file in the root directory of vue.config.jsconduct webpack configuration, which will cover vue-cli in webpack default configuration

vue.config.js :
const VueSSRServerPlugin = require("vue-server-renderer/server-plugin")
const VueSSRClientPlugin = require("vue-server-renderer/client-plugin")

//环境变量,决定入口是客户端还是服务端
const TARGRT_NODE = process.env.WEBPACK_TARGET === "node"
const target = TARGRT_NODE ? "server" : "client"

module.exports = {
    
    
    css: {
    
    
        extract: false
    },
    outputDir: "./dist/" + target,
    configureWebpack: () => ({
    
    
        //将 entry 指向应用程序的 server entry 文件
        entry: `./src/entry-${
      
      target}.js`,
        //对 bundle renderer 提供 source map 支持
        devtool: "source-map",
        //这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import)
        //并且还会在编译 Vue 组件时,告知 `vue-loader` 输送面向服务器代码(server-oriented code)
        target: TARGRT_NODE ? "node" : "web",
        node: TARGRT_NODE ? undefined : false,
        output: {
    
    
            //此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)
            libraryTarget: TARGRT_NODE ? "commonjs2" : undefined
        },
        optimization: {
    
     splitChunks: TARGRT_NODE ? false : undefined },
        //将服务器的整个输出构建为单个 JOSN 文件的插件
        //服务端默认文件名为 vue-ssr-server-bundle.json
        plugins: [TARGRT_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()]
    })
}

Packaging script configuration

cross-envPlug-in: Run scripts for
cross- platform settings and use environment variables Install cross-env plugin

npm install cross-env --save

In the package.jsondefinition file project run packaging script

package.json:
{
    
    
	......
	"scripts": {
    
    
		"server": "node server",
	    "build:client": "vue-cli-service build",
	    "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build --mode server",
	    "build": "npm run build:server && npm run build:client"
	},
	......
}

Terminal execution command package project:

npm run build

After the packaging is complete, the terminal executes the command to start the Node.js server

npm run server

After the server is started, the browser can open localhost:9999 to access the SSR project.
Check the source code of the webpage and find that a special attribute has been added to the root element:, data-server-renderedwhich lets the client Vue know that this part of HTML is rendered by Vue on the server And should be mounted in active mode

<div id="app" data-server-rendered="true">......</div>

Insert picture description here

Project directory:

Insert picture description here

After packaging the dist directory:

Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_45426836/article/details/109305304