跟我学习搭建一个SSR

Vue SSR 介绍

SSR是什么

  • 官方文档:https://ssr.vuejs.org/
  • Vue SSR(Vue.js Server-Side Rendering) 是 Vue.js 官方提供的一个服务端渲染(同构应用)解决方案。
  • 使用它可以构建同构应用。
  • 还是基于原有的 Vue.js 技术栈。

官方文档的解释:Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出Vue组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。
服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器客户端上运行。

使用场景

在对你的应用程序使用服务器端渲染 (SSR) 之前,你应该问的第一个问题是,是否真的需要它。

技术层面:

  • 更快的首屏渲染速度
  • 更好的 SEO

业务层面:

  • 不适合管理系统
  • 适合门户资讯类网站,例如企业官网、知乎、简书等
  • 适合移动网站

如何实现 Vue SSR

(1)基于 Vue SSR 官方文档提供的解决方案
官方方案具有更直接的控制应用程序的结构,更深入底层,更加灵活,同时在使用官方方案的过程中,也会对Vue SSR有更加深入的了解。该方式需要你熟悉 Vue.js 本身,并且具有 Node.js 和 webpack 的相当不错的应用经验。

(2)Nuxt.js 开发框架
NUXT提供了平滑的开箱即用的体验,它建立在同等的Vue技术栈之上,但抽象出很多模板,并提供了一些额外的功能,例如静态站点生成。通过 Nuxt.js 可以快速的使用 Vue SSR 构建同构应用。

Vue SSR 基本使用

渲染一个 Vue 实例

目标:了解如何使用 VueSSR 将一个 Vue 实例渲染为 HTML 字符串。

服务端渲染中最基础的工作:模板渲染。即如何在服务端使用 Vue 的方式解析替换字符串。

mkdir vue-ssr
cd vue-ssr
npm install vue vue-server-renderer
// 第 1 步:创建一个 Vue 实例
const Vue = require("vue");
const app = new Vue({
   
 template: `<div>{
    { message }}</div>`,
 data: {
   
  message: "Hello World",
},
});
// 第 2 步:创建一个 renderer
const renderer = require("vue-server-renderer").createRenderer();
// 第 3 步:将 Vue 实例渲染为 HTML
renderer.renderToString(app, (err, html) => {
   
 if (err) throw err;
 console.log(html);
 // => <div data-server-rendered="true">Hello World</div>
});
// 在 2.5.0+,如果没有传入回调函数,则会返回 Promise:
renderer
.renderToString(app)
.then((html) => {
   
  console.log(html);
})
.catch((err) => {
   
  console.error(err);
});

与服务器集成

在 Node.js 服务器中使用时相当简单直接,例如 Express。
首先安装 Express 到项目中:

npm i express

然后使用 Express 创建一个基本的 Web 服务:

const express = require("express");
const app = express();
app.get("/", (req, res) => {
   
 res.send("Hello World!");
});
app.listen(3000, () => console.log("app listening at http://localhost:port"));

启动 Web 服务:

nodemon .\server.js

在 Web 服务中渲染 Vue 实例:

const Vue = require('vue')
const express = require('express')
const fs = require('fs')
const renderer = require('vue-server-renderer').createRenderer({
   
    //方法三、模板方式
    template: fs.readFileSync('./index.template.html', 'utf-8')
})

const server = express()

server.get('/', (req, res) => {
   
    const app = new Vue({
   
        template: `
            <div id="app">
                <h1>{
    {message}}</h1>
            </div>
        `,
        data: {
   
            message: '牛年大吉'
        }
    })

    renderer.renderToString(app, {
   
        title: 'hello',
        meta: `
        <meta name="description" content='牛年'>
    ` }, (err, html) => {
   
        if (err) {
   
            return res.status(500).end('Internal Server Error.')
        }
        //方法一、设置响应头编码格式
        res.setHeader('Content-Type', 'text/html;charset=utf8')
        //方法二、meta标签
        res.end(html)
    })
})

server.listen(3000, () => {
   
    console.log('server running at port 3000.');
})

使用一个页面模板

创建index.template.html文件:

<!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.0">
    {
   {
   {
   meta}}}
    <title>{
   {
   title}}</title>
</head>

<body>
    <!--vue-ssr-outlet-->
</body>
</html>

构建同构渲染

构建流程在这里插入图片描述

  • Server Bundle:做服务端渲染。
  • Client Bundle:接管服务端渲染好的静态页面,对它进行激活,把它激活成一个动态的客户端页面。

源码结构

为了实现将相同的 Vue 应用程序提供给客户端,我们需要在服务器上使用 webpack 打包 Vue 应用程序,因为:

  • 通常 Vue 应用程序是由 webpack 和 vue-loader 构建,并且许多 webpack 特定功能不能直接在 Node.js 中运行(例如通过 file-loader 导入文件,通过 css-loader 导入 CSS)。
  • 尽管 Node.js 最新版本能够完全支持 ES2015 特性,我们还是需要转译客户端代码以适应老版浏览器。这也会涉及到构建步骤。

基本看法是,对于客户端应用程序和服务器应用程序,我们都要使用 webpack 打包 - 服务器需要「服务器 bundle」然后用于服务器端渲染(SSR),而「客户端 bundle」会发送给浏览器,用于混合静态标记。

使用 webpack 的源码结构

现在我们正在使用 webpack 来处理服务器和客户端的应用程序,大部分源码可以使用通用方式编写,可以使用 webpack 支持的所有功能。同时,在编写通用代码时,有一些事项要牢记在心。

一个基本项目可能像是这样:在这里插入图片描述
App.vue

<template>
  <!-- 客户端渲染的入口节点 -->
 <div id="app">
  <h1>牛年大吉</h1>
 </div>
</template>
<script>
export default {
   
 name: 'App'
}
</script>
<style>
</style>

app.js

app.js 是我们应用程序的「通用 entry」。在纯客户端应用程序中,我们将在此文件中创建根 Vue 实例,并直接挂载到 DOM。但是,对于服务器端渲染(SSR),责任转移到纯客户端 entry 文件。app.js 简单地使用 export 导出一个 createApp 函数:

import Vue from 'vue'
import App from './App.vue'

// 导出一个工厂函数,用于创建新的
// 应用程序、router 和 store 实例
export function createApp () {
   
  const app = new Vue({
   
    // 根实例简单的渲染应用程序组件。
    render: h => h(App)
  })
  return {
    app }
}

entry-client.js

客户端 entry 只需创建应用程序,并且将其挂载到 DOM 中:

import {
    createApp } from './app'

// 客户端特定引导逻辑……

const {
    app } = createApp()

// 这里假定 App.vue 模板中根元素具有 `id="app"`
app.$mount('#app')

entry-server.js

服务器 entry 使用 default export 导出函数,并在每次渲染中重复调用此函数。此时,除了创建和返回应用程序实例之外,它不会做太多事情 - 但是稍后我们将在此执行服务器端路由匹配 (server-side route matching) 和数据预取逻辑 (data pre-fetching logic)。

import {
    createApp } from './app'

export default context => {
   
  const {
    app } = createApp()
  //服务器端路由匹配、数据预取逻辑
  return app
}

构建配置

安装依赖

(1)安装生产依赖

npm i vue vue-server-renderer express cross-env

在这里插入图片描述
(2)安装开发依赖

npm i -D webpack webpack-cli webpack-merge webpack-node-externals @babel/core
@babel/plugin-transform-runtime @babel/preset-env babel-loader css-loader url-
loader file-loader rimraf vue-loader vue-template-compiler friendly-errors-
webpack-plugin

在这里插入图片描述

配置文件及打包命令

(1)初始化 webpack 打包配置文件

build
├── webpack.base.config.js # 公共配置
├── webpack.client.config.js # 客户端打包配置文件
└── webpack.server.config.js # 服务端打包配置文件

webpack.base.config.js

/**
* 公共配置
*/
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const path = require('path')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
const resolve = file => path.resolve(__dirname, file)
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
   
    mode: isProd ? 'production' : 'development',
    output: {
   
        path: resolve('../dist/'),
        publicPath: '/dist/',
        filename: '[name].[chunkhash].js'
    },
    resolve: {
   
        alias: {
   
            // 路径别名,@ 指向 src
            '@': resolve('../src/')
        },
        // 可以省略的扩展名
        // 当省略扩展名的时候,按照从前往后的顺序依次解析
        extensions: ['.js', '.vue', '.json']
    },
    devtool: isProd ? 'source-map' : 'cheap-module-eval-source-map',
    module: {
   
        rules: [
            // 处理图片资源
            {
   
                test: /\.(png|jpg|gif)$/i,
                use: [
                    {
   
                        loader: 'url-loader',
                        options: {
   
                            limit: 8192
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值