SvelteKit 3.0 把 $lib 别名改成了 #lib,并且要求模块导入写显式扩展名。这个改动波及面很大,值得单独讲清楚。
为什么要改
$lib 是 SvelteKit 自定义的别名,需要工具链特殊处理。
#lib 走的是 Node 的子路径导入(subpath imports)规范,也就是 package.json 里的 imports 字段。这是标准机制,不依赖框架私有约定。
好处很直接:
- 编辑器、类型检查器、构建工具都能原生理解,不需要插件支持。
- 和 nodenext 模块解析配合得更好。
- 减少了框架特定的魔法,配置更可预测。
3.0.1 补丁修的正是这个 3.0.1 修的是生成的类型,让相对导入在 nodenext 模块解析下可用。这说明别名改动和模块解析是配套的一组变更。
迁移要做两件事
- 全局把
$lib替换成#lib。 - 给导入路径补上显式扩展名。
第二件容易被忽略,但它是必须的。在 nodenext 解析下,不带扩展名的相对导入会报错。
迁移步骤建议
- 先确认环境:Node 22+、TypeScript 6、Svelte 5.56.4+、Vite 8、@sveltejs/vite-plugin-svelte v7。
- 用编辑器全局替换
$lib→#lib。 - 跑一遍类型检查,所有报「找不到模块」的地方基本都是缺扩展名,逐个补。
- 重点检查动态导入和字符串拼接的导入路径——这类写法全局替换覆盖不到,必须手动找。
第 4 条最容易漏
如果你的代码里有 import(...) 这种动态导入,而且路径是拼接出来的,静态替换工具不会碰它,类型检查也不一定能发现。必须全局搜 import( 手动过一遍。
顺便要处理的其他 3.0 变更
$app/stores被移除,要换成$app/state。$service-worker被移除。handleValidationError被移除,校验错误现在带kind: validation进入handleError。
安全默认收紧也别漏
默认禁止外部重定向,没有 Content-Type 头的跨站表单提交被拒绝,以 x-sveltekit- 开头的查询参数被拒绝。
如果有 OAuth 回调或者外部系统集成,专门测一遍。
一句话总结 这个改动的方向是对的——用标准机制替代框架私有约定,长期看减少摩擦。但迁移期是一次性的痛,别名替换加补扩展名加安全检查,工作量比看起来大。
本文由奇幻维度内容助手整理发布,欢迎在评论区交流你的看法。