如何在基于Vite构建的Vue SSR项目中正确集成Vue Router?
问题原因
- 当前
entry-server.js、entry-client.js中未完成路由注册、服务端路径匹配逻辑,仅创建了根App实例,仅能渲染App.vue的默认内容 - 服务端收到请求后未把当前访问路径传递给服务端路由做匹配,路由无法识别需要渲染的对应组件
- 根组件App.vue中未添加
<router-view>占位符,路由匹配到的组件没有渲染出口
注意:SSR场景下路由、全局状态管理类实例必须每次请求创建新实例,不可复用单例,避免多请求之间数据污染。
修复步骤
1. 路由配置调整(/src/router/index.js)
import { createRouter, createMemoryHistory, createWebHistory } from 'vue-router' // 导入自定义路由组件 import Home from './views/Home.vue' import About from './views/About.vue' // 导出路由创建函数,每次调用生成全新路由实例 export function createMyRouter() { return createRouter({ // 服务端使用内存历史模式,客户端使用浏览器历史模式 history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(), routes: [ { path: '/', component: Home }, { path: '/about', component: About } // 其余路由按实际需求补充 ] }) }
2. entry-server.js 修改
import { createApp } from "vue"; import { renderToString } from "@vue/server-renderer"; import App from "./App.vue"; import { createMyRouter } from './router' // 新增接收请求路径参数 export async function render(url) { const app = createApp(App); const router = createMyRouter() app.use(router) // 路由跳转到当前请求路径,等待路由加载完成后再渲染 await router.push(url) await router.isReady() const appContent = await renderToString(app); return appContent; }
3. entry-client.js 修改
import { createApp } from "vue"; import App from "./App.vue"; import { createMyRouter } from './router' const app = createApp(App); const router = createMyRouter() app.use(router) // 等待客户端路由就绪后再挂载,避免hydration不匹配问题 router.isReady().then(() => { app.mount("#app"); })
4. main.js 修改
const { createServer } = require("vite"); const server = require("express")(); const fs = require("fs"); const path = require("path"); async function main() { const vite = await createServer({ server: { middlewareMode: true } }); server.use(vite.middlewares); server.get("*", async (req, res) => { let html = fs.readFileSync(path.resolve(__dirname, "index.html"), "utf-8"); const { render } = await vite.ssrLoadModule("/src/entry-server.js"); // 把当前请求的路径传递给服务端渲染方法 const appContent = await render(req.url); html = html.replace("<!--ssr-->", appContent); res.end(html); }); server.listen(8080); } main();
5. App.vue 新增路由占位符
在App.vue模板的对应渲染位置添加路由出口:
<template> <!-- 原有App.vue的公共布局内容 --> <router-view></router-view> </template>
内容的提问来源于stack exchange,提问作者Sergio AC
相关产品推荐
相关产品推荐

