Ionic 6 Vue项目接入SSR并部署需求求助
Ionic 6 + Vue.js SSR 添加与部署解决方案
一、依赖配置与脚本更新
- 安装SSR核心依赖
npm install @vue/server-renderer express npm install -D vue3-client-only
- 修改
package.json的脚本命令,添加客户端/服务端构建及启动命令:
{ "scripts": { "dev": "vite", "build:client": "vite build --outDir dist/client", "build:server": "vite build --ssr src/main.ts --outDir dist/server", "build": "npm run build:client && npm run build:server", "serve": "node dist/server/server.js" } }
二、重构main.ts为SSR兼容模式
将直接挂载应用的逻辑改为工厂函数,确保服务端每次请求都生成全新的应用实例:
// src/main.ts import { createSSRApp } from 'vue' import { createStore } from 'vuex' import App from './App.vue' import router from './router' // 导出应用创建工厂函数,供客户端/服务端调用 export function createApp() { // 初始化Vuex Store(保留你的原有状态配置) const store = createStore({ state: () => ({ /* 你的状态定义 */ }), mutations: { /* 你的mutations */ }, actions: { /* 你的actions */ }, modules: { /* 你的模块 */ } }) const app = createSSRApp(App) app.use(store) app.use(router) return { app, router, store } } // 客户端专属挂载逻辑 if (import.meta.env.SSR === false) { const { app, router, store } = createApp() // 恢复服务端注入的初始状态 if (window.__INITIAL_STATE__) { store.replaceState(window.__INITIAL_STATE__) } router.isReady().then(() => { app.mount('#app') }) }
三、创建服务端入口文件server.ts
在项目根目录创建server.ts,用Express处理服务端渲染逻辑:
// server.ts import express from 'express' import { renderToString } from '@vue/server-renderer' import { createApp } from './src/main' import fs from 'fs' import path from 'path' const app = express() const PORT = process.env.PORT || 3000 // 读取客户端构建的HTML模板 const template = fs.readFileSync(path.resolve(__dirname, './dist/client/index.html'), 'utf-8') // 静态资源托管 app.use('/assets', express.static(path.resolve(__dirname, './dist/client/assets'))) // 处理所有路由的SSR渲染 app.get('*', async (req, res) => { const { app, router, store } = createApp() // 设置当前请求路由 await router.push(req.url) await router.isReady() // 调用路由组件的异步数据获取逻辑(如果有) const matchedComponents = router.currentRoute.value.matched.flatMap(record => Object.values(record.components)) await Promise.all( matchedComponents.map(component => { if (component.asyncData) { return component.asyncData({ store, route: router.currentRoute.value }) } }) ) // 渲染应用为HTML字符串 const appHtml = await renderToString(app) // 序列化Vuex状态,供客户端恢复 const initialState = JSON.stringify(store.state) // 注入渲染内容与初始状态到模板 const finalHtml = template .replace('<!--app-html-->', appHtml) .replace('<!--initial-state-->', `<script>window.__INITIAL_STATE__ = ${initialState}</script>`) res.send(finalHtml) }) app.listen(PORT, () => { console.log(`SSR服务运行在 http://localhost:${PORT}`) })
四、调整HTML模板占位符
修改public/index.html,添加服务端渲染的内容与状态占位符:
<!-- public/index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ionic Vue SSR App</title> </head> <body> <div id="app"><!--app-html--></div> <!--initial-state--> <script type="module" src="/src/main.ts"></script> </body> </html>
五、处理Ionic组件的SSR兼容性
部分Ionic组件依赖浏览器DOM环境,需用<ClientOnly>包裹这类组件,确保只在客户端渲染:
<template> <ClientOnly> <ion-modal :is-open="showModal"> <!-- 模态框内容 --> </ion-modal> </ClientOnly> </template> <script setup> import { ClientOnly } from 'vue3-client-only' import { ref } from 'vue' const showModal = ref(false) </script>
或者在组件的onMounted钩子中处理DOM相关逻辑(onMounted仅在客户端执行)。
六、服务器部署步骤
- 将项目代码上传至服务器,执行
npm install安装依赖 - 执行构建命令:
npm run build - 启动SSR服务:
npm run serve - (可选)用PM2管理进程,避免服务意外中断:
pm2 start dist/server/server.js --name ionic-ssr-app
关键注意事项
- 确保Vuex状态可序列化,避免存储函数、Symbol等无法转为JSON的内容
- 路由中的异步组件需确保在服务端渲染前加载完成
- API请求需在服务端路由就绪后调用(通过
asyncData方法),确保数据预取完成再渲染HTML
内容的提问来源于stack exchange,提问作者Khaled Omara
相关产品推荐
相关产品推荐

