From 7ecacd65207ee1d7ca6b9938bfdaf9a2fd9783e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=9E=E5=8F=AF=20=C2=B7=20YU=20KE?= <1798456934@qq.com> Date: Mon, 31 Aug 2026 10:32:07 +0800 Subject: [PATCH] fix(@vben-core/preferences): avoid unscoped storage before init (#8329) --- .changeset/quiet-caches-wait.md | 5 +++ .../preferences/__tests__/preferences.test.ts | 38 +++++++++++++++++++ packages/@core/preferences/src/preferences.ts | 4 +- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .changeset/quiet-caches-wait.md diff --git a/.changeset/quiet-caches-wait.md b/.changeset/quiet-caches-wait.md new file mode 100644 index 000000000..092cf6878 --- /dev/null +++ b/.changeset/quiet-caches-wait.md @@ -0,0 +1,5 @@ +--- +'@vben-core/preferences': patch +--- + +fix(@vben-core/preferences): avoid unscoped localStorage before initialization diff --git a/packages/@core/preferences/__tests__/preferences.test.ts b/packages/@core/preferences/__tests__/preferences.test.ts index 6afdb2182..5c50792a9 100644 --- a/packages/@core/preferences/__tests__/preferences.test.ts +++ b/packages/@core/preferences/__tests__/preferences.test.ts @@ -61,6 +61,44 @@ describe('preferences', () => { expect(preferences).toEqual(defaultPreferences); }); + it('uses memory storage until preferences are initialized', async () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + vi.useFakeTimers(); + + try { + const manager = new PreferenceManager(); + manager.updatePreferences({ app: { locale: 'en-US' } }); + await vi.advanceTimersByTimeAsync(151); + + expect(localStorage.setItem).not.toHaveBeenCalled(); + + await manager.initPreferences({ + namespace: 'testNamespace', + }); + vi.mocked(localStorage.setItem).mockClear(); + + manager.updatePreferences({ app: { locale: 'en-US' } }); + await vi.advanceTimersByTimeAsync(151); + + expect(localStorage.setItem).toHaveBeenCalledWith( + 'testNamespace-preferences', + expect.any(String), + ); + expect( + vi + .mocked(localStorage.setItem) + .mock.calls.every(([key]) => key.startsWith('testNamespace-')), + ).toBe(true); + expect(warnSpy).not.toHaveBeenCalledWith( + expect.stringContaining('empty prefix'), + ); + } finally { + vi.clearAllTimers(); + warnSpy.mockRestore(); + vi.useRealTimers(); + } + }); + it('initializes preferences with overrides', async () => { const overrides: any = { app: { diff --git a/packages/@core/preferences/src/preferences.ts b/packages/@core/preferences/src/preferences.ts index 80677da05..68653dab1 100644 --- a/packages/@core/preferences/src/preferences.ts +++ b/packages/@core/preferences/src/preferences.ts @@ -10,7 +10,7 @@ import type { import { markRaw, reactive, readonly, watch } from 'vue'; -import { StorageManager } from '@vben-core/shared/cache'; +import { MemoryStorageDriver, StorageManager } from '@vben-core/shared/cache'; import { isMacOs, merge, @@ -44,7 +44,7 @@ class PreferenceManager { private state: Preferences; constructor() { - this.cache = new StorageManager(); + this.cache = new StorageManager({ driver: new MemoryStorageDriver() }); // 构造函数不再同步读取缓存,使用默认值初始化 // 真正的缓存加载在 initPreferences 中完成(已经是 async) this.state = reactive({ ...defaultPreferences });