
sveltekit 默认启用服务端渲染(ssr),而 localstorage 是浏览器专属 api,在服务端(node.js 环境)中不可用,直接调用会导致构建失败。本文详解根本原因、推荐检测方式、安全使用模式及 ssr/csr 分离实践。
sveltekit 默认启用服务端渲染(ssr),而 localstorage 是浏览器专属 api,在服务端(node.js 环境)中不可用,直接调用会导致构建失败。本文详解根本原因、推荐检测方式、安全使用模式及 ssr/csr 分离实践。
在 SvelteKit(基于 Vite)项目中,当你在 .ts 或 .svelte 文件中直接使用 localStorage.getItem() 时,Vite 构建流程会同时生成客户端(browser)和服务端(server)两套代码。而服务端运行于 Node.js 环境,全局对象 window 和其子属性 localStorage 均不存在——这正是报错 ReferenceError: localStorage is not defined 的根本原因。
✅ 正确做法:环境检测 + 条件执行
最稳妥的方式是显式判断当前代码是否运行在浏览器环境,仅在浏览器中执行 localStorage 操作。SvelteKit 提供了两种官方推荐方式:
方式一:使用 $app/environment 中的 browser 标志(推荐 ✅)
import { browser } from '$app/environment';
if (browser) {
const db_exists_key = 'database-exists';
const db_exists = localStorage.getItem(db_exists_key);
if (db_exists !== 'exists') {
await initUnitsAndDimensions();
await initCalculator();
localStorage.setItem(db_exists_key, 'exists');
}
}
✅ 优势:类型安全、零运行时开销(SvelteKit 在编译期可静态分析并剔除服务端分支)、语义清晰。
方式二:传统 typeof window !== 'undefined' 检测(兼容但非最优)
if (typeof window !== 'undefined') {
const db_exists_key = 'database-exists';
const db_exists = localStorage.getItem(db_exists_key);
if (db_exists !== 'exists') {
await initUnitsAndDimensions();
await initCalculator();
localStorage.setItem(db_exists_key, 'exists');
}
}
⚠️ 注意:该方式虽有效,但在服务端仍会保留 if 判断逻辑(无法被 Tree-shaking 移除),且缺乏类型提示支持。
⚠️ 关键注意事项
不要在 +server.ts 或 +page.server.ts 中使用 localStorage:这些文件纯服务端执行,browser 为 false,window 一定不存在。
-
避免在 load 函数顶层同步访问 localStorage:即使加了 browser 判断,若 load 被服务端调用,异步初始化逻辑(如 await initXXX())可能被跳过,导致状态不一致。建议将初始化逻辑移至客户端组件(如 onMount)或 +layout.svelte 中:
<!-- +layout.svelte --> <script lang="ts"> import { onMount } from 'svelte'; import { browser } from '$app/environment'; onMount(async () => { if (browser) { const key = 'database-exists'; if (localStorage.getItem(key) !== 'exists') { await initUnitsAndDimensions(); await initCalculator(); localStorage.setItem(key, 'exists'); } } }); </script> 替代方案考虑:若需持久化服务端可读的配置,应改用 cookies(通过 cookies.set())或后端数据库;localStorage 仅适用于纯前端状态缓存。
✅ 总结
| 场景 | 推荐方案 |
|---|---|
| 初始化逻辑需仅在浏览器执行 | 使用 if (browser) { ... } + $app/environment |
| 需确保服务端完全不执行相关代码 | browser 检测优于 typeof window(编译期优化) |
| 涉及用户首次访问行为(如引导、初始化) | 放入 onMount,避免 SSR 与 CSR 状态冲突 |
| 需跨请求持久化且服务端需感知 | 改用 HTTP cookies 或服务端存储 |
遵循以上原则,即可彻底规避 localStorage is not defined 构建错误,并构建出健壮、可维护的 SvelteKit 应用。











