Vuexy模板(Vite+Vue3+Vuetify)添加SSR遇window/localStorage未定义问题
解决方案
1. 环境判断:隔离浏览器API调用
所有涉及localStorage、window的代码,必须先判断当前运行环境是否为浏览器,避免服务端执行时报错:
- 直接在代码中添加判断:
if (typeof window !== 'undefined') { // 仅在客户端执行浏览器相关操作 const savedTheme = localStorage.getItem('app-theme') window.addEventListener('resize', handleResize) } - 封装工具函数复用,减少重复代码:
在组件或状态管理中导入使用:// utils/browser-utils.js export const isClient = () => typeof window !== 'undefined' export const getStorageItem = (key) => isClient() ? localStorage.getItem(key) : null export const setStorageItem = (key, val) => isClient() && localStorage.setItem(key, val)import { getStorageItem } from '@/utils/browser-utils' const userPrefs = getStorageItem('user-preferences')
2. Pinia状态管理适配SSR
Pinia在SSR场景下每个请求需要独立实例,且禁止在store初始化阶段调用浏览器API:
- 修改store逻辑,将依赖浏览器API的初始化逻辑移到actions中,在客户端生命周期钩子触发:
// stores/app.js import { defineStore } from 'pinia' export const useAppStore = defineStore('app', { state: () => ({ theme: 'light' }), actions: { initClientState() { if (typeof window !== 'undefined') { this.theme = localStorage.getItem('app-theme') || 'light' } } } }) - 在组件的
onMounted钩子中调用初始化方法(服务端不会执行该钩子):import { useAppStore } from '@/stores/app' import { onMounted } from 'vue' const appStore = useAppStore() onMounted(() => { appStore.initClientState() })
3. Vuetify主题配置调整
避免在Vuetify实例初始化阶段读取localStorage,改为客户端挂载后动态更新:
// main.js import { createApp } from 'vue' import { createVuetify } from 'vuetify' // 基础主题配置(服务端渲染时使用默认值) const vuetify = createVuetify({ theme: { defaultTheme: 'light' } }) const app = createApp(App) app.use(vuetify) // 客户端挂载后读取本地存储并更新主题 if (typeof window !== 'undefined') { const savedTheme = localStorage.getItem('app-theme') if (savedTheme) { vuetify.theme.global.name.value = savedTheme } } app.mount('#app')
4. 第三方插件/组件适配
如果项目中存在直接依赖window的插件(如Vuexy自带的主题插件),调整加载时机:
- 动态导入插件,仅在客户端环境加载:
// main.js 或插件注册文件 if (typeof window !== 'undefined') { import('@/plugins/theme-plugin').then(module => { app.use(module.default) }) } - 若插件源码可修改,直接在插件内部添加环境判断,包裹所有浏览器API调用逻辑。
5. Vite SSR配置优化
确保Vite正确区分客户端与服务端打包逻辑:
// vite.config.js export default defineConfig({ ssr: { noExternal: ['vuetify'] // 确保Vuetify被SSR兼容处理 }, build: { ssr: true, rollupOptions: { input: { server: './src/entry-server.js', client: './src/entry-client.js' } } } })
内容的提问来源于stack exchange,提问作者tareq safia
相关产品推荐
相关产品推荐

