diff --git a/packages/utils/src/storage.ts b/packages/utils/src/storage.ts index 5dd8cdc..b33323b 100644 --- a/packages/utils/src/storage.ts +++ b/packages/utils/src/storage.ts @@ -3,61 +3,101 @@ import localforage from 'localforage'; /** The storage type */ export type StorageType = 'local' | 'session'; +// 内存存储的备用实现 +class MemoryStorage { + private static instance: MemoryStorage; + private storage = new Map(); + + static getInstance() { + if (!MemoryStorage.instance) { + MemoryStorage.instance = new MemoryStorage(); + } + return MemoryStorage.instance; + } + + setItem(key: string, value: string) { + this.storage.set(key, value); + } + + getItem(key: string) { + return this.storage.get(key) || null; + } + + removeItem(key: string) { + this.storage.delete(key); + } + + clear() { + this.storage.clear(); + } +} + +// 全局备用存储实例 +const memoryStorage = MemoryStorage.getInstance(); + export function createStorage(type: StorageType) { - const stg = type === 'session' ? window.sessionStorage : window.localStorage; + // 尝试获取存储实例,如果失败则使用内存存储 + let stg: Storage | MemoryStorage; + + try { + stg = type === 'session' ? window.sessionStorage : window.localStorage; + // 测试存储是否可用 + stg.setItem('__storage_test__', ''); + stg.removeItem('__storage_test__'); + } catch (e) { + console.warn(`${type} storage is not available, using memory storage`); + stg = memoryStorage; + } const storage = { - /** - * Set session - * - * @param key Session key - * @param value Session value - */ set(key: K, value: T[K]) { - const json = JSON.stringify(value); - - stg.setItem(key as string, json); + try { + const json = JSON.stringify(value); + stg.setItem(key as string, json); + } catch (e) { + console.warn(`Storage set error, falling back to memory storage`); + memoryStorage.setItem(key as string, JSON.stringify(value)); + } }, - /** - * Get session - * - * @param key Session key - */ + get(key: K): T[K] | null { - const json = stg.getItem(key as string); - if (json) { - let storageData: T[K] | null = null; - + try { + const json = stg.getItem(key as string); + if (!json) return null; + return JSON.parse(json); + } catch (e) { + console.warn(`Storage get error, trying memory storage`); try { - storageData = JSON.parse(json); - } catch {} - - if (storageData) { - return storageData as T[K]; + const memoryValue = memoryStorage.getItem(key as string); + return memoryValue ? JSON.parse(memoryValue) : null; + } catch { + return null; } } - - stg.removeItem(key as string); - - return null; }, + remove(key: keyof T) { - stg.removeItem(key as string); + try { + stg.removeItem(key as string); + memoryStorage.removeItem(key as string); + } catch (e) { + console.warn(`Storage remove error`); + } }, + clear() { - stg.clear(); + try { + stg.clear(); + memoryStorage.clear(); + } catch (e) { + console.warn(`Storage clear error`); + } } }; + return storage; } -type LocalForage = Omit & { - getItem(key: K, callback?: (err: any, value: T[K] | null) => void): Promise; - - setItem(key: K, value: T[K], callback?: (err: any, value: T[K]) => void): Promise; - - removeItem(key: keyof T, callback?: (err: any) => void): Promise; -}; type LocalforageDriver = 'local' | 'indexedDB' | 'webSQL'; @@ -68,9 +108,97 @@ export function createLocalforage(driver: LocalforageDriver) { webSQL: localforage.WEBSQL }; - localforage.config({ - driver: driverMap[driver] - }); + // 创建一个内存存储的备用实现 + const memoryStore = new Map(); - return localforage as LocalForage; + // 创建备用存储对象 + const fallbackStorage = { + getItem(key: K): Promise { + return Promise.resolve(memoryStore.get(key as string) || null); + }, + setItem(key: K, value: T[K]): Promise { + memoryStore.set(key as string, value); + return Promise.resolve(value); + }, + removeItem(key: keyof T): Promise { + memoryStore.delete(key as string); + return Promise.resolve(); + }, + clear(): Promise { + memoryStore.clear(); + return Promise.resolve(); + }, + length(): Promise { + return Promise.resolve(memoryStore.size); + }, + key(keyIndex: number): Promise { + return Promise.resolve(Array.from(memoryStore.keys())[keyIndex]); + }, + keys(): Promise { + return Promise.resolve(Array.from(memoryStore.keys())); + } + }; + + try { + // 配置 localforage + localforage.config({ + driver: [ + driverMap[driver], + localforage.LOCALSTORAGE, + localforage.INDEXEDDB, + localforage.WEBSQL + ].filter(Boolean), + name: 'appStorage', + version: 1.0, + storeName: 'keyvaluepairs' + }); + + // 创建包装的存储对象 + const storage = { + getItem(key: K): Promise { + return localforage.getItem(key as string) + .catch(() => fallbackStorage.getItem(key)); + }, + setItem(key: K, value: T[K]): Promise { + return localforage.setItem(key as string, value) + .catch(() => fallbackStorage.setItem(key, value)); + }, + removeItem(key: keyof T): Promise { + return localforage.removeItem(key as string) + .catch(() => fallbackStorage.removeItem(key)); + }, + clear(): Promise { + return localforage.clear() + .catch(() => fallbackStorage.clear()); + }, + length(): Promise { + return localforage.length() + .catch(() => fallbackStorage.length()); + }, + key(keyIndex: number): Promise { + return localforage.key(keyIndex) + .catch(() => fallbackStorage.key(keyIndex)); + }, + keys(): Promise { + return localforage.keys() + .catch(() => fallbackStorage.keys()); + } + }; + + return storage as LocalForage; + } catch (e) { + console.warn('Localforage initialization failed, using memory storage', e); + return fallbackStorage as LocalForage; + } +} + +// 更新类型定义 +interface LocalForage { + getItem(key: K): Promise; + setItem(key: K, value: T[K]): Promise; + removeItem(key: keyof T): Promise; + clear(): Promise; + length(): Promise; + key(keyIndex: number): Promise; + keys(): Promise; } diff --git a/vite.config.ts b/vite.config.ts index 97e3d7c..5bf9e36 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -29,7 +29,8 @@ export default defineConfig(configEnv => { open: false, proxy: createViteProxy(viteEnv, configEnv.command === 'serve'), fs: { - cachedChecks: false + cachedChecks: false, + strict: false // 添加这个配置 } }, preview: { @@ -40,6 +41,24 @@ export default defineConfig(configEnv => { sourcemap: viteEnv.VITE_SOURCE_MAP === 'Y', commonjsOptions: { ignoreTryCatch: false + }, + // 添加以下配置 + rollupOptions: { + output: { + manualChunks: undefined, // 禁用代码分割 + chunkFileNames: 'assets/js/[name]-[hash].js', + entryFileNames: 'assets/js/[name]-[hash].js', + assetFileNames: 'assets/[ext]/[name]-[hash].[ext]' + } + }, + // 添加以下配置 + chunkSizeWarningLimit: 2000, + minify: 'terser', + terserOptions: { + compress: { + drop_console: true, + drop_debugger: true + } } } };