使用vite搭建ssr活动页架构的实现

目录
  • 前言
  • 入门SSR
    • 什么是SSR
    • ssr的历史
    • csr的缺点
    • 为什么ssr的需求再次出现
    • 如何实现基础ssr
      • 创建服务端
      • 渲染vue
      • 客户端渲染
      • 网页路由
      • 服务端路由
      • 客户端路由
      • 比较两种方式
  • 使用vite做ssr
    • vps的约定式路由
      • dev阶段
    • build阶段
    • 项目大了之后,打包速度慢该怎么办?
    • 快速创建页面模板
    • 做得不好的地方
    • 部署
    • 源码地址

前言

最近接了个需求,重构公司的活动页项目。要实现:

  • SEO良好
  • MPA
  • 启动速度快,构建速度快
  • 前端工程化
  • 浏览器兼容至少IE11

基于这些需求,我选择了 vite + react + vite-plugin-ssr

文章前面是ssr入门,老手请随意跳过,看最后即可

入门SSR

什么是SSR

术语

  • ssr,全名 server side render,服务端渲染
  • csr,全名 client side render,客户端渲染
  • spa,全名 single page application,单页面应用
  • mpa,全名 multi page application,多页面应用

ssr的历史

我的学习习惯是,不论学什么,先去了解它的历史背景。存在即合理,了解到为什么产生一个技术,能让我更容易去理解这门技术

最初的网页渲染,前端三剑客:html + css + js,放在服务器上,静态部署就可以供用户访问了。

后来随着网页复杂度上升,出现了jsp/ejs等等一系列模板语法,在服务端获取到数据后,把数据渲染到模板中,最后生成html返回给客户端,这是最原始的ssr。

随着前端框架的诞生(ng/react/vue),越来越多同学开始使用框架开发web,这些前端框架的出现使得前后端开发解耦(csr的情况下),前端同学可以更充分的利用前端工程化等等新技术来健壮前端项目。而这种完全解耦的方式也带来了一些问题,比如非常不友好的SEO

csr的缺点

让我们打开一个SPA网页(使用脚手架默认方式搭建),右键查看网页源代码

第一个问题:SEO极度不友好。 网页里面根本没有内容。爬虫最喜欢这种网页了,看一眼就走。

SPA的工作方式就是使用js来动态渲染html,压力全部给到了客户端(浏览器)这边,正是因为这个,第二个问题也出现了:首屏的加载速度较慢

为什么ssr的需求再次出现

为了更好的SEO,为了更快的加载速度(服务端生成了首页静态页面,客户端可以直接展示,随后再用JS动态渲染)

前端开发使用react/vue,可以熟练开发网页。而cra/vue-cli脚手架创建出来的模板默认是SPA。

那么应该如何实现 “既要,还要”呢(前端框架/seo我全都要)

如何实现基础ssr

基于上面的问题,我们希望实现:

  • 查看网页源代码时,展示网页的内容

既然需要服务端渲染,服务端用来执行vue/react这种js框架,那第一反应就是用nodejs来做服务端渲染,因为nodejs天然执行js代码

客户端的话,用vue来做(react也行,只不过最近在熟悉vue3),vue3的话,体积比react更小,toC网站更好一些。react18针对ssr出了新api,开发者可以使用 React.lazysuspense 实现懒加载,也提供了很好的用户体验:https://github.com/reactwg/react-18/discussions/37

下面是基础的ssr例子

以下例子 请注意:客户端使用的是esm规范,服务端使用的是cjs

如果希望统一使用esm,可以使用 tsx 执行node脚本 或修改package.json => type: "module"

创建服务端

const express = require('express')

const app = express()

app.get('*', (req, res) => {
  res.send('Hello World')
})

app.listen(4000, () => {
  console.log('Server running at http://localhost:4000');
})

启动服务后,打开浏览器 http:localhost:4000,即可看到内容

渲染vue

服务端有了,但是是返回的string,我们想用vue来开发,尝试返回一个vue组件

vue3提供了服务端渲染组件的方法,在 vue/server-renderer

const express = require('express')
const { renderToString } = require('vue/server-renderer')
const { createSSRApp } = require('vue')

const app = express()

app.get('*', (req, res) => {
  const vue = createSSRApp({
    data: () => ({ count: 1 }),
    template: `<button @click="count++">{{ count }}</button>`,
  })

  renderToString(vue).then((html) => {
    res.send(`
    <!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">
      <title>Document</title>
    </head>
    <body>
      <div id="app">${html}</div>
    </body>
    </html>
    `)
  })
})

app.listen(4000, () => {
  console.log('Server running at http://localhost:4000')
})

此时打开页面,可以看到button了,但是此时页面是静态的,因为这个页面在服务端已经渲染好了,但在客户端没有注入vue

右键查看网页源代码,可以看到button元素

客户端渲染

我们希望button的交互可以动起来,此时需要客户端来做渲染了

const { createSSRApp } = require('vue')

const vue = createSSRApp({
  data: () => ({ count: 1 }),
  template: `<button @click="count++">{{ count }}</button>`,
})

vue.mount('#app')

这段代码是否很眼熟,其实基本上跟服务端渲染返回的内容是一样的。所以ssr的本质是服务端渲染静态html+客户端渲染js

此外,为了在浏览器中加载客户端文件,我们还需要:

  • server.js中添加 server.use(express.static('.')) 来托管客户端文件。这里要注意js执行顺序
  • <script type="module" src="/client.js"></script>添加到 HTML 外壳以加载客户端入口文件
  • 通过在 HTML 外壳中添加 Import Map 以支持在浏览器中使用 import * from 'vue'
const express = require('express')
const { renderToString } = require('vue/server-renderer')
const { createSSRApp } = require('vue')

const app = express()

app.get('/', (req, res) => {
  const vue = createSSRApp({
    data: () => ({ count: 1 }),
    template: `<button @click="count++">{{ count }}</button>`,
  })

  renderToString(vue).then((html) => {
    res.send(`
    <!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">
      <title>Document</title>
      <script type="importmap">
      {
        "imports": {
          "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
        }
      }
      </script>
      <script src="/client.js" type="module"></script>
    </head>
    <body>
      <div id="app">${html}</div>
    </body>
    </html>
    `)
  })
})

app.use(express.static('.'))

app.listen(4000, () => {
  console.log('Server running at http://localhost:4000')
})

此时打开本地地址,可以看到点击button数字变化了

以上是最简单的ssr,在vue官网上可以找到这个例子。

我们甚至没有去考虑前端的路由,状态管理 等等。一个完整的ssr还需要一系列构建。

网页路由

ssr的网页路由有两种方式

  • 服务端路由
  • 客户端路由

服务端路由

服务端路由,就是利用 web框架的路由能力,匹配到某个路由时,返回对应的html代码,并且加载相应的客户端代码,比如:

import express from 'express'

const router = express.Router()

router.get('/some-page', (req, res) => {
  // 返回 some-page 的html
  res.send(`<!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">
      <title>Document</title>
      <script src="/client.js" type="module"></script>
    </head>
    <body>
      <div id="app">要渲染的html字符串</div>
    </body>
    </html>`)
})

服务端路由跳转直接使用 a标签即可

客户端路由

客户端路由的话,就要用到前端框架对应的路由库,vue-router / react-router 等

可以参照官方例子

比较两种方式

服务端路由适合做页面零碎的项目,如活动页,每次跳转路由会刷新整个页面

客户端路由适合做页面之间交互强的项目,如产品页,跳转路由不会刷新页面

使用vite做ssr

vue官方推荐了几个做ssr的例子,包括 Nuxt/ Quasar这种重框架,也有vite的轻框架。为了细粒度把控项目,我使用了 vite+ vite-plugin-ssr的方案来做

vite-plugin-ssr

Like Next.js / Nuxt but as do-one-thing-do-it-well Vite plugin.

类似 Next/Nuxt 但是只做一件事并把它做好 的vite插件

这个插件的文档写得非常详细,而且github上有许多例子。

插件的具体功能我不赘述,各位可看官方文档,我在这里讲一下这个插件(v0.3x)的约定式路由的工作原理。以下 vite-plugin-ssr 简称为 vps

vps的约定式路由

vps推荐使用文件夹名称作为路由,这种方式也是最方便的。活动页不存在页面之间的交互,所以我选择的默认方式。

vps规定了一系列文件命名,作为开发/构建遍历的条件。以下4种命名会被vps收集,每种文件有其独特的作用。我们不要随意以 page.*** 来命名文件

// Vite resolves globs with micromatch: https://github.com/micromatch/micromatch
// Pattern `*([a-zA-Z0-9])` is an Extglob: https://github.com/micromatch/micromatch#extglobs
export const pageFiles = {
  //@ts-ignore
  '.page': import.meta.glob('/**/*.page.*([a-zA-Z0-9])'),
  //@ts-ignore
  '.page.client': import.meta.glob('/**/*.page.client.*([a-zA-Z0-9])'),
  //@ts-ignore
  '.page.server': import.meta.glob('/**/*.page.server.*([a-zA-Z0-9])'),
  //@ts-ignore
  '.page.route': import.meta.glob('/**/*.page.route.*([a-zA-Z0-9])'),
}

dev阶段

  • node启动服务端server,调用 vps 的createPageRenderer,返回了 renderPage方法,我们调用 renderPage 即可获取到服务端渲染后的内容。源码地址
  • vps在vite的dev阶段,设置了 optimizeDeps做依赖预构建的优化。(咱们也可以参考这块源码对vite项目进行一些优化)。 源码地址

build阶段

  • 针对 client / server 分别打包。如果使用约定式路由,会根据上文讲到的遍历条件,遍历所有文件后,把所有的 .page文件设置为 input 的每一项(MPA)。源码地址
  • 生成vps的manifest文件,其命名为 vite-plugin-ssr.json,里面会存放一些vps的基本信息。源码地址
  • 生成单个的server bundled代码,供部署使用,名为 importBuild.js源码地址
  • 生成 package.json。 如果我们指定打包为es,则package.json中的type = module,否则为 commonjs。源码地址
  • page.server的代码转为固定的一个导出语句,用来判断 page.server是否有导出。源码地址
  • 移除vite的内置钩子 vite:ssr-require-hook(我们如果想魔改插件钩子,可以参考这种方法)源码地址

项目大了之后,打包速度慢该怎么办?

做活动页,每个页面之间是没有关联的,其实我希望打包是增量式的打包,但是如果公共文件改变了,也无法避免全量打包。所以如果能做到缓存打包文件,就可以提升打包速度。

理想美好,现实往往相反。rollup2并不支持content hash,但是好消息是rollup3支持了并且会在最近发布

目前我们只能用hack的方式去实现content hash,比如使用node的 crypto模块来做md5hash

import { createHash } from 'crypto'
import type { PreRenderedChunk } from 'rollup'

export function getContentHash(chunk: string | Uint8Array) {
  return createHash('md5').update(chunk).digest('hex').substring(0, 6)
}

export function getHash(chunkInfo: PreRenderedChunk) {
  return getContentHash(
    Object.values(chunkInfo.modules)
      .map((m) => m.code)
      .join(),
  )
}

然后在rollup的output中设置文件的命名

rollupOptions: {
  treeshake: 'smallest',
  output: {
    format: 'es',
    assetFileNames: (assetInfo) => {
      let extType = path.extname(assetInfo.name || '').split('.')[1]
      if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType!)) {
          extType = 'img'
          }
      const hash = getContentHash(assetInfo.source)
      return `assets/${extType}/[name].${hash}.[ext]`
    },

    chunkFileNames: (chunkInfo) => {
      const server = chunkInfo.name.endsWith('server') ? 'server-' : ''
      const name = chunkInfo.facadeModuleId?.match(/src/pages/(.*?)//)?.[1] || chunkInfo.name

      if (chunkInfo.isDynamicEntry || chunkInfo.name === 'vendor') {
        const hash = getHash(chunkInfo)
        return `assets/js/${name}-${server}${hash}.chunk.js`
      } else {
        return `assets/js/${name}-${server}[hash].chunk.js`
      }
    },
    entryFileNames: (chunkInfo) => {
      if (chunkInfo.name === 'pageFiles') {
        return '[name].js'
      }
      const hash = getHash(chunkInfo)
      return `assets/js/entry-${hash}.js`
    },
  },
},

做了content-hash后,打包速度会有非常大的提升,因为rollup其实有个cache机制,针对cache的文件不会transform,而正好transform是非常耗时的一步。

我尝试了打包1000个文件,耗时40+s,在我的接受范围内

快速创建页面模板

活动页面会有比较多相似的地方,所以直接根据模板来创建页面代码,开发效率又高一点(又可以摸鱼了)。代码地址

做得不好的地方

记录两个ssr探索过程中,我想实现,但最后没有实现的

  • 按需打包。因为做活动页,按理说架构应该是按需打包,做完一个页面打包一个页面。尝试了用monorepo,这样打包的话,那么就要启动多个服务来监听。不用monorepo的话,就需要在rollup打包的过程中,设置outdir,然后打包在指定目录中。同理,也需要启动多个服务。要做到只启动一个服务,就得每次打包服务端都全量打包,客户端按需打包,那么服务端和客户端之间相互引用的文件路径就很难去控制了。之所以想做按需打包,其实就是担心以后项目大了打包慢。如果rollup的打包性能可以跟上的话,在接受范围内的话,其实是不需要做按需打包的
  • 按需启动。启动指定路由文件,而不去遍历整个项目。这个得等vps0.4了

部署

部署的话,打算使用docker来做,下篇文章再讲

源码地址

react + ssr

vue3 + ssr

到此这篇关于使用vite搭建ssr活动页架构的实现的文章就介绍到这了,更多相关vite搭建ssr活动页内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解vue服务端渲染(SSR)初探

    前言 首先来讲一下服务端渲染,直白的说就是在服务端拿数据进行解析渲染,直接生成html片段返回给前端.具体用法也有很多种比如: 传统的服务端模板引擎渲染整个页面 服务渲染生成htmll代码块, 前端 AJAX 获取然后js动态添加 服务端渲染的优劣 首先是seo问题,前端动态渲染的内容是不能被抓取到的,而使用服务端渲染就可以解决这个问题.还有就是首屏加载过慢这种问题,比如在SPA中,打开首页需要初始加载很多资源,这时考虑在首屏使用服务端渲染,也是一种折中的优化方案.但是使用SSR时,势必会增加服

  • 通过vue-cli3构建一个SSR应用程序的方法

    1.前沿 1.1.什么是SSR SSR(服务端渲染)顾名思义就是将页面在服务端渲染完成后在客户端直接展示. 1.2.客户端渲染与服务端渲染的区别 传统的SPA模式 即客户端渲染的模式 Vue.js构建的应用程序,默认情况下是有一个html模板页,然后通过webpack打包生成一堆js.css等等资源文件.然后塞到index.html中 用户输入url访问页面 -> 先得到一个html模板页 -> 然后通过异步请求服务端数据 -> 得到服务端的数据 -> 渲染成局部页面 ->

  • 更强大的vue ssr实现预取数据的方式

    我在前几天的一篇文章中吹了两个牛皮,截图为证: 现在可以松口气的说,这两个牛皮都实现了,不过 vue-suspense 改名了,叫做 vue-async-manager 了,他能帮你管理 Vue 应用中的异步组件的加载和 API 的调用,提供了与 React Suspense 同名的 `<Suspense>` 组件,Github: shuidi-fed/vue-async-manager ​ github.com 第二个牛皮是在开发 vue-async-manager 的过程中临时产生的一个灵

  • 简单的Vue SSR的示例代码

    前言 最近接手一个老项目,典型的 Vue 组件化前端渲染,后续业务优化可能会朝 SSR 方向走,因此,就先做些技术储备.如果对 Vue SSR 完全不了解,请先阅读官方文档. 思路 Vue 提供了一个官方 Demo,该 Demo 优点是功能大而全,缺点是对新手不友好,容易让人看蒙.因此,今天我们来写一个更加容易上手的 Demo.总共分三步走,循序渐进. 写一个简单的前端渲染 Demo(不包含 Ajax 数据): 将前端渲染改成后端渲染(仍然不包含 Ajax 数据): 在后端渲染的基础上,加上 A

  • 基于vue-ssr服务端渲染入门详解

    第一部分 基本介绍 1.前言 服务端渲染实现原理机制:在服务端拿数据进行解析渲染,直接生成html片段返回给前端.然后前端可以通过解析后端返回的html片段到前端页面,大致有以下两种形式: 1.服务器通过模版引擎直接渲染整个页面,例如java后端的vm模版引擎,php后端的smarty模版引擎. 2.服务渲染生成html代码块, 前端通过AJAX获取然后使用js动态添加. 2.服务端渲染的优劣 服务端渲染能够解决两大问题: 1.seo问题,有利于搜索引擎蜘蛛抓取网站内容,利于网站的收录和排名.

  • 浅谈Vue SSR 的 Cookies 问题

    一个网站一旦涉及到多用户, 就很难从 Cookies 中逃脱, Vue SSR 的 cookies 也真算是遇到的一个不小的问题, 从开始玩 SSR 开始到现在, 一共想出了3种方案, 从最早的把 Cookies 注入到 state 中, 到把 Cookies 注入到 global, 到现在的将 Cookies 注入到组件的 asyncData 方法. 随着 Vue 的升级, 第一种方案已经不再适用, 第二种也有不少的限制, 于是想到第三种方案, 下来就说说具体实现的方法: 第一种方案 第一种方

  • 15分钟学会vue项目改造成SSR(小白教程)

    15分钟学会vue项目改造成SSR Ps:网上看了好多服务器渲染的例子,基本都是从0开始的,用Nuxt或者vue官网推荐的ssr方案(vue-server-renderer),但是我们在开发过程中基本上是已经有了现有的项目了,我们所要做的是对现有项目的SSR改造.那么这里,跟我一起对一个vue-cil2.0生成的项目进行SSR改造 关于这篇文章的案例源代码我放在我的github上面,有兴趣的同学,也可以去我的github查看我之前写的博客.博客 一.改造技术的分析对比. 一般来说,我们做seo有

  • 详解Vue2 SSR 缓存 Api 数据

    本文介绍了Vue2 SSR 缓存 Api 数据,分享给大家,具体如下: 1. 安装缓存依赖: lru-cache npm install lru-cache --dev 2. api 配置文件 config-server.js var LRU = require('lru-cache') let api if (process.__API__) { api = process.__API__ } else { api = process.__API__ = { api: 'http://loca

  • 使用vite搭建ssr活动页架构的实现

    目录 前言 入门SSR 什么是SSR ssr的历史 csr的缺点 为什么ssr的需求再次出现 如何实现基础ssr 创建服务端 渲染vue 客户端渲染 网页路由 服务端路由 客户端路由 比较两种方式 使用vite做ssr vps的约定式路由 dev阶段 build阶段 项目大了之后,打包速度慢该怎么办? 快速创建页面模板 做得不好的地方 部署 源码地址 前言 最近接了个需求,重构公司的活动页项目.要实现: SEO良好 MPA 启动速度快,构建速度快 前端工程化 浏览器兼容至少IE11 基于这些需求

  • 用vite搭建vue3应用的实现方法

    一,安装 提示: VUE3.0目前还没有官方的翻译文档.但是已经有人翻译了.得到了尤雨溪大佬的点赞,这里附上网址https://v3.cn.vuejs.org/ 1.安装 cli 因为要使用 vue3 必须要求 cli 的版本比较高,必须要高于 4.5.X 所以没有安装的 cli 的就直接安装最新版就行了,已有的可以升级或者卸载后重新安装 最好是全局安装 //全局安装 npm install -g @vue/cli # OR yarn global add @vue/cli //全局卸载 npm

  • Vite搭建React项目的方法步骤

    前言 日常放鸽,火钳刘明 这是一个基于 vite 搭建的 React 的项目,开发体验非常棒. 创建一个 Vite 项目 yarn create @vitejs/app 如上图,选择了 react-ts 预设模板,如果出现下图一样的工程 yarn // 安装依赖 yarn dev // 启动开发环境 打开浏览器输入http://localhost:3000/#/,如上图所示的话.那么恭喜你,你可以正常开发 React 项目了.完结撒花 如果不行的话,直接看 vite 官网,它比我写的详细 改造工

  • 使用Lvs+Nginx集群搭建高并发架构的实现示例

    目录 1. Lvs介绍 2. Lvs 负载均衡模式 2.1 NAT 2.2 TUN 2.3 DR模式 3. Lvs DR模式配置 3.1 Vip配置 3.2 LVS集群管理工具安装 3.3 地址解析协议 3.4 集群配置 高并发站点不仅要考虑网站后端服务的稳定,还需要考虑服务能否接入巨大流量.承受巨大流量,如下图: 1:流量接入,可以采用Lvs+Nginx集群,这种方式能接入的QPS能高达数百万 2:通过Lvs实现Nginx集群,Nginx+Tomcat实现后端服务集群,完成了从接入层流量处理到

  • 利用Vite搭建Vue3+ElementUI-Plus项目的全过程

    目录 创建项目 初始化项目 添加依赖并运行 添加路由 添加依赖 添加路由配置文件 在main.js中添加路由 添加Home页面进行测试 添加ElementUI-Plus 安装element-plus依赖 引入element-plus依赖 引入Element Icon 添加依赖 修改element的主题颜色 总结 本文主要记录使用Vite搭建一个Vue3+ElementUI-Plus,以及集成Vue Router的过程.本次搭建过程的Nodejs版本为 V16.14.2 创建项目 初始化项目 使用

  • 如何使用vite搭建vue3项目详解

    目录 一:npm构建 二:更改http://localhost:3000/到8080与Network路由访问 三:配置vite别名(npm install @types/node --save-dev) 四 :路由(npm install vue-router@4) 五:vuex(npm install vuex@next --save) 六:Eslint(可选)(npm install --save-dev eslint eslint-plugin-vue) 七:less/sass(可选)(n

  • vite搭建vue2项目的实战过程

    目录 问题提出 搭建过程 1.初始化项目 1.1 创建项目 1.2 安装vite对vue2支持的插件 1.3 安装vue依赖 1.4 修改项目文件结构 1.5 运行一下项目 2.vue-router 2.1 安装 2.2 新建router目录 2.3 全局注册 3.vuex 3.1 安装 3.2 新建vuex目录 3.3 全局注册 4.组件库 4.1 安装 4.2 按需引入 4.3 在main.js全局注册 4.4 在页面中使用 5.axios 5.1 安装 5.2 封装axios 5.3 在页

  • 使用Vite搭建vue3+TS项目的实现步骤

    目录 vite简介 初始化项目 修改vite.config.ts 安装ts依赖和ESLint 安装Axios 配置跨域 安装Less vite简介 vite 是一个基于 Vue3 单文件组件的非打包开发服务器,它具有快速的冷启动,不需要等待打包操作:并且官网说是下一代的前端构建工具. 初始化项目 npm init vite@latest 1.输入项目名称 2.选择Vue 3.选择TS 4.启动项目 5.项目启动成功 注意 用vscode进行开发的时候,推荐使用volar,禁用以前vue2常使用的

  • 详解MySQL高可用MMM搭建方案及架构原理

    先来看看架构,如下图: 部署 1.修改hosts 在所有的服务器中执行相同的操作. vim /etc/hosts 192.168.137.10 master 192.168.137.20 backup 192.168.137.30 slave 192.168.137.40 monitor 2.添加mysql用户 只需要在所有的数据库端执行即可,监控端不需要. GRANT REPLICATION CLIENT ON *.* TO 'mmm_monitor'@'192.168.137.%' IDEN

  • vue/vue-cli+express手把教你搭建SSR

    最近简单的研究了一下SSR,对SSR已经有了一个简单的认知,主要应用于单页面应用,Nuxt是SSR很不错的框架.也有过调研,简单的用了一下,感觉还是很不错.但是还是想知道若不依赖于框架又应该如果处理SSR,研究一下做个笔记. 什么是SSR 把Vue组件渲染为服务器端的HTML字符串,将他们直接发送到浏览器,最后将静态标记混合为客户端上完全交互的应用程序. 为什么要使用SSR 更好的SEO,搜索引擎爬虫爬取工具可以直接查看完全渲染的页面 更宽的内容达到时间(time-to-content),当权请

随机推荐