预渲染、服务端渲染(SSR)学习笔记

2,116 阅读3分钟

预渲染:构建阶段生成匹配预渲染路径的 html 文件(注意:每个需要预渲染的路由都有一个对应的 html)。构建出来的 html 文件已有部分内容

服务端渲染:用户访问 url,服务端根据访问路径请求所需数据,拼接成 html 字符串,返回给前端。前端接收到 html 时已有部分内容;

第一部分:预渲染(Prerending)(prerender-spa-plugin)

一、搭建

1.vue init webpack
2.npm install
3.npm run dev
4.npm install prerender-spa-plugin -D

二、添加路由组件,并把vue路由配置为history模式

mode: 'history'

三、开始使用配置

1.https://github.com/chrisvfritz/prerender-spa-plugin(webpack里面配置使用方法网址)

2.webpack.prod.conf.js配置

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const PrerenderSPAPlugin = require('prerender-spa-plugin')


new PrerenderSPAPlugin({
    staticDir: path.join(__dirname, '../dist'),
    routes: ['/', '/about'],
    renderer: new Renderer({
        inject: {
            foo: 'far'
        },
        headless: false,
        // 在项目的入口中使用document.dispatchEvent(new Event('render-event'))
        renderAfterDocumentEvent: 'render-event'
    })
}),


3.main.js配置

mounted() {
    document.dispatchEvent(new Event('render-event'))
}

四、打包、启动

1.打包

// 生成dist文件
npm run build

2.服务器端启动,使用到了 http-server

// 控制台 cd dist,执行下方命令
hs -o -p 9999

五、浏览器f12查看NetWork->Response下的内容


首次请求可以看到已经有内容了~优秀

第二部分:服务端渲染(SSR)(vue-server-renderer)【待更新,学习中ing】

一、定义+优点

1.什么是服务端渲染?(Server Side Rendering)

Vue.js是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出Vue组件,进行生成DOM和操作DOM,然而也可以将同一个组件渲染为服务器端的HTML字符串,将它们直接发送到浏览器,最后将这些静态标记“激活”为客户端上完全可交互的应用程序。


2.服务端渲染优点有哪些?

  • 更快的构建速度,SSR是动态插入数据,并不会在构建时就去预加载数据,而是输入url后在服务端请求,拿到返回的数据插入模板后再返回给客户端。
  • 嵌套路由下的个性化页面加载速度,个性化页面无法进行预渲染,ssr却可以解决。
  • 更好的SEO。
  • 更快的首屏加载速度。( 请求业务数据,和将数据转为html片段都在服务端进行了,浏览器负责加载资源,请求CDN资源,css渲染。到达时间缩短。之后走的依旧是前端路由,然后前端预取数据,所以这里仅仅首屏 )。
                                                      下图为听课贴图


二、简单搭建

1.init创建项目

1) npm init --yes
2) npm i vue express vue-server-renderer -S // 安装 vue、express服务端应用框架、vue-server-renderer

2.创建server.js文件

const Vue = require('vue')
const express = require('express')() // 创建服务端的渲染器
const renderer = require('vue-server-renderer').createRenderer()
const app = new Vue({
    template:'<div>hello world</div>'
})
express.get('/',(req,res)=>{
    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>
        `)
    })
})
express.listen(8080,()=>{
    console.log('服务器已经启动!')
})


解读:


3.启动查看

node server.js

4.浏览器f12查看NetWork->Response已经有了html内容

三、配置文件

1.打开一个之前webpack构建好的vue项目


2.把server.js添加进去,如上图最下方

3.配置package.json,添加命令

"server": "webpack --config build/webpack.server.conf.js"


4.添加并配置/build/webpack.server.conf.js文件

5.注释入口文件

入口文件不再是main.js,应该是服务端的入口文件,接下来配置


6.添加入口文件entry-server.js


解决vue单例的问题,实现每次点击都调用

7.更改main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import {createRouter} from './router'
Vue.config.productionTip = false
// 单例
/* eslint-disable no-new */
export function createApp() {
    const router = createRouter()
    const app = new Vue({
        router,
        components: { App },
        template: '<App/>'
    })  
    return { app }}
}

8.更改router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import About from '@/components/About'
import Home from '@/components/Home'
Vue.use(Router)
export function createRouter() {
    return new Router({
        mode: 'history',
        routes: [
            {
                path: '/',
                name: 'Home',
                component: Home
            }, 
            {
                path: '/about',
                name: 'About',
                component: About
            }
        ]
    })
}

9.配置entry-server.js

import { createApp } from './main'
export default context => {
    return new Promise((resolve, reject)=> {
        const { app } = createApp
        const router = app.$router
        const { url } = context
        const { fullPath } = router.resolve(url).route
        if (fullPath !== url) {
            return reject({url: fullPath})
        }
        // 更改路由
        router.push(url)
        // wait until router has resolved possible async hooks
        router.onReady(()=> {
            const matchedComponents = router.getMatchedComponents()
            // no matched routes
            if (!matchedComponents.length) {
                return reject({code: 404})
            }
            resolve(app)
        }, reject)
    })
}

10.执行命令

npm run server