软件教程 2025年08月6日
0 收藏 0 点赞 663 浏览 4122 个字
摘要 :

文章目录 一、项目结构概览 二、Vite配置详解 (一)server/app.vite.ts (二)vite.config.ts 三、客户端与服务端入口文件及公共逻辑 (一)entry-client.ts (二)……




  • 一、项目结构概览
  • 二、Vite配置详解
    • (一)server/app.vite.ts
    • (二)vite.config.ts
  • 三、客户端与服务端入口文件及公共逻辑
    • (一)entry-client.ts
    • (二)entry-server.ts
    • (三)main.ts
    • (四)路由配置
  • 四、SSR渲染实现

Vue的服务端渲染(SSR)技术能有效提升应用的性能和用户体验。以往,大家常用Nuxt来实现Vue的SSR功能。不过在实际项目开发里,会碰到各种各样的情况。比如说,有些项目架构复杂,除了SSR功能外,还得兼顾后端接口聚合、AB实验以及多语言支持等业务需求,这时候Nuxt就有点力不从心了。还有一些老项目,最初不是基于Nuxt搭建的,而是使用webpack来实现SSR。另外,有时候团队为了遵循自定义的规范,不想受Nuxt设计规范的限制。基于这些原因,本文就来详细讲讲如何快速集成一个express+vite+vue3的SSR项目模板

一、项目结构概览

在开始搭建之前,先了解一下这个项目的整体结构,如下:

project
  - client
      - pages # 存放每个页面的代码
          - about
          - home
      - routes # 路由
      - App.vue
      - entry-client.ts # 客户端入口
      - entry-server.ts # 服务端入口
      - main.ts
  - server
      - app.vite.ts
  - vite
      - vite-ssr.ts
      - vite.config.ts

可以看到,项目主要分为clientservervite这几个部分,每个部分都承担着不同的职责。client目录存放与客户端相关的代码,server目录用于服务器端的配置,vite目录则包含Vite相关的配置文件。

二、Vite配置详解

(一)server/app.vite.ts

server/app.vite.ts这个文件很关键,它主要负责启动Vite开发服务器,并将其集成到Express服务中。具体代码如下:

import express from \'express\'
import { createServer } from \'vite\'
import { viteSsrRender } from \'../vite/vite-ssr\'

const app = express()
const root = process.cwd()

async function startServer() {
  // 通过createServer方法以代码方式启动Vite开发服务器,而不是用命令行启动,这样能更方便地集成到node服务端代码里
  const vite = await await createServer({
    configFile: `${root}/vite/vite.config.ts`,
  })

  //vite.middlewares用于处理静态资源请求,比如.ts、.vue文件,同时支持热模块替换(HMR)功能
  app.use(vite.middlewares)

  // 处理所有的HTTP请求
  app.get(\'*\', async (req, res) => {
    // 进行SSR渲染
    const html = await viteSsrRender(req, res, { vite })
    // 将渲染后的HTML内容返回给客户端
    res.status(200).set({ \'Content-Type\': \'text/html\' }).end(html)
  })

  // 启动服务器,监听3000端口
  app.listen(3000, () => {
    console.log(\'Server is running at http://localhost:3000\')
  })
}

startServer()

(二)vite.config.ts

vite.config.ts是Vite的配置文件,在这里可以对Vite的各种行为进行设置。代码如下:

import { defineConfig } from \'vite\'
import vue from \'@vitejs/plugin-vue\'

export default defineConfig({
  // 启用Vue插件,让Vite支持Vue项目的构建
  plugins: [vue()],
  server: {
    // 开启中间件模式,便于将Vite集成到自定义的Node服务器中,而不是让Vite单独运行
    middlewareMode: true,
  },
  // 不自动处理HTML文件,开发者需要手动控制HTML的生成和渲染
  appType: \'custom\',
})

三、客户端与服务端入口文件及公共逻辑

(一)entry-client.ts

entry-client.ts是客户端渲染或激活的入口文件,代码如下:

import { createApp } from \'./main\'

async function main() {
  // 创建Vue应用实例和路由实例
  const { app, router } = createApp()
  // 等待路由准备就绪
  await router.isReady()
  // 将Vue应用挂载到id为app的DOM元素上
  app.mount(\'#app\')
}
main()

(二)entry-server.ts

entry-server.ts作为服务端渲染的入口文件,代码如下:

import { createApp as _createApp } from \'./main\'

export async function createApp(context: { url: string }) {
  // 创建Vue应用实例和路由实例
  const { app, router } = _createApp()

  // 检查上下文对象中是否包含url,若没有则报错
  if (!context.url) {
    console.error(\'context.url is required\')
  }
  // 将当前请求的URL手动添加到路由中
  router.push(context.url) 
  // 等待路由准备就绪
  await router.isReady()

  return { app }
}

(三)main.ts

main.ts文件包含了客户端和服务端共享的公共逻辑,代码如下:

import { createSSRApp } from \'vue\'
import App from \'./App.vue\'
import { createRouterInstance } from \'./routes\'

export function createApp() {
  // 创建一个用于SSR的Vue应用实例
  const app = createSSRApp(App)
  // 创建路由实例
  const router = createRouterInstance()

  // 将路由挂载到Vue应用上
  app.use(router)

  return { app, router }
}

(四)路由配置

在路由配置中,由于服务端没有浏览器的history api,所以需要根据运行环境选择不同的history模式。代码如下:

import { createRouter, createMemoryHistory, createWebHistory } from \'vue-router\'

export function createRouterInstance() {
  // 判断当前代码是在服务端还是客户端执行
  const isServer = typeof window === \'undefined\'

  return createRouter({
    // 根据环境选择不同的history模式
    history: isServer ? createMemoryHistory() : createWebHistory(),
    routes: [
      {
        path: \'/about\',
        // 动态导入about页面的组件
        component: () => import(\'../pages/about/App.vue\'),
        name: \'about\'
      },
      {
        path: \'/\',
        // 动态导入home页面的组件
        component: () => import(\'../pages/home/App.vue\'),
        name: \'home\',
      },
    ],
  })
}

四、SSR渲染实现

最后,来看一下SSR渲染的具体实现代码。viteSsrRender函数负责将Vue应用渲染为HTML字符串,并返回给客户端。

import path from \'node:path\'
import { renderToString } from \'vue/server-renderer\'

const root = process.cwd()

export async function viteSsrRender (req, res, { vite }) {
  try {
    // 获取服务端渲染入口文件的路径
    const entryServerPath = path.join(root, \'client/entry-server.ts\')
    // 动态加载服务端渲染的入口文件
    const createApp = (await vite.ssrLoadModule(entryServerPath)).createApp
    // 注入所需上下文数据并执行
    const { app } = await createApp({ url: req.url })
    // 将Vue应用渲染为HTML字符串
    const renderedHtml = await renderToString(app)

    // 构建完整的HTML页面
    const html = `
      <!DOCTYPE html>
      <html>
        <head>
          <title>SSR App</title>
        </head>
        <body>
          <div id=\"app\">${renderedHtml}</div>
          <script type=\"module\" src=\"/client/entry-client.ts\"></script>
        </body>
      </html>
    `
    return html
  } catch (e) {
    // 若渲染过程中出现错误,打印错误信息并返回空字符串
    console.error(e)
    return \'\'
  }
}

通过以上步骤,我们就完成了一个express+vite+vue3的SSR项目模板的搭建。希望这篇文章能帮助大家在实际项目开发中顺利运用SSR技术。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/6845.html

管理员

相关推荐
2025-08-06

文章目录 一、Promise基础回顾 二、Promise 与 axios 结合使用场景及方法 (一)直接返回 axios …

269
2025-08-06

文章目录 一、模块初始化时的内部机制 二、常见导出写法的差异分析 (一)写法一:module.exports…

107
2025-08-06

文章目录 一、ResizeObserver详解 (一)ResizeObserver是什么 (二)ResizeObserver的基本用法 …

683
2025-08-06

文章目录 一、前期准备工作 (一)下载相关文件 (二)安装必要工具 二、处理扣子空间生成的文件…

338
2025-08-06

文章目录 一、官方文档 二、自动解包的数据类型 ref对象:无需.value即可访问 reactive对象:保持…

371
2025-08-06

文章目录 一、Hooks的工作原理 二、在if语句中使用Hook会出什么岔子? 三、React官方的Hook使用规…

843
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号