[Full Clock 技术复盘] 二、SvelteKit 实战避坑指南:PWA、SSR 样式断裂、持久化防抖
在 SvelteKit 2 不要用vite-plugin-pwa,否则你还要去找各种文件;套了 i18n 你就更不知道生成文件的目录了,导致前端每次都会报错:
workbox-3105ea8d.js:1 Uncaught (in promise) non-precached-url: non-precached-url :: [{"url":"index.html"}] |
at O.createHandlerBoundToURL (workbox-3105ea8d.js:1:13313) |
at Object.createHandlerBoundToURL (workbox-3105ea8d.js:1:14966) |
at sw.js:1:1398 |
at sw.js:1:558 |
在 SvelteKit 2 环境下,强烈建议使用官方内置的$service-worker:$service-worker • 文档 • Svelte - Svelte 框架
全智能处理,框架原生支持。
Svelte SSR 样式断裂
对于在用户端会重新渲染(与屏幕大小关联,或与用户自定义主题关联)的情况,SSR 渲染产物和用户实际期待画面会不一致。这时,会造成首屏样式的断裂。
解决方法:加 CSStransition,用户感觉还是自然进入自己设置的主题。
localStorage 缓存踩坑
之前为了优化localStorage被反复写入的情况,加了这样一段代码:
let settings = $state({ theme: 'dark', fontSize: 16 }); |
$effect(() => { |
debouncedSave(settings); |
}); |
function debouncedSave(data: any) { |
clearTimeout(timer); |
timer = setTimeout(() => { |
localStorage.setItem('settings', JSON.stringify(data)); |
}, 300); |
} |
这个防抖乍看没什么问题,但是代码一旦上线,问题可就大了——设置数据永远不会被保存。
为什么呢?因为 Svelte 的$effect只会追踪同步执行路径上被访问到的属性,记录其为依赖。既然数据读取发生在setTimeout的异步中,Svelte 自然也无从得知,便认为该$effect没有依赖——这就麻烦大了。
解决方案:
$effect(() => { |
const snapshot = $state.snapshot(settings); |
debouncedSave(snapshot); |
}); |
$state.snapshot访问了每一个属性,从而将其转换成了 JavaScript 对象。这样一来,就实现了依赖记录和追踪。