- Web框架
- 后端
- 前端
【免费下载链接】kit
web development, streamlined
@sveltejs/package是 SvelteKit 仓库中负责将src/lib源码编译为可分发包(dist)的官方工具,其命令行入口为svelte-package。本文以该包在仓库中的 CHANGELOG.md 为主线,结合 src 下的真实实现代码与 test/index.spec.js 测试用例,系统梳理从 2.x 到 3.0.0-next 的关键能力演进、CLI 参数、别名解析、类型声明生成、server-only 文件防护等核心机制。读完本文,你将能理解svelte-package的构建流水线原理,并掌握写出"可直接发布"的 Svelte 组件库所需的全部配置细节。
1. 定位:构建 Svelte 包的正确姿势
@sveltejs/package的目标是"用正确格式构建 Svelte 包"(见 README.md)。它把通常位于src/lib下的组件与模块源码:
- 扫描并处理所有
.svelte、.ts、.js文件,将.ts转译为 JS、剥离lang/type预处理标签; - 生成类型声明(
.d.ts/.d.mts/.d.cts); - 解析路径别名(如
$lib、#开头的 import)为相对导入; - 复制静态资源,最终输出到
dist目录。
包入口定义在 package.json 的bin字段("svelte-package": "svelte-package.js"),该脚本仅一行:import './src/cli.js'(见 svelte-package.js),真正的参数解析与命令分发都在 src/cli.js 中完成。
与 SvelteKit 应用不同,
svelte-package面向的是组件库/工具库作者,产出物必须能被任意 Svelte 项目(甚至非 SvelteKit 项目)正常消费。
2. 版本基调:3.0.0-next 的破坏性变化
CHANGELOG 记录了@sveltejs/package3.x 预发布阶段的几项重大调整,其中最关键的是两条Major Changes:
2.1 要求 Node 22 或更高
3.0.0-next.0与3.0.0-next.5两次声明breaking: require Node 22 or newer。这一点与 package.json 中的engines: { "node": ">=22" }完全一致。如果你在 CI 或本机使用旧版 Node,需要先升级到 Node 22+ 再运行svelte-package。
2.2 依赖收敛:移除 sade 与 kleur
3.0.0-next.4和3.0.0-next.5连续移除了sade(命令行解析库)与kleur(颜色输出库),改用 Node 内置能力。从 src/cli.js 可以看到,如今参数解析使用node:util的parseArgs,彩色输出使用styleText——这既减少了依赖树体积,也让包在 Node 22 下的行为更一致。
2.3 配置读取迁移到@sveltejs/load-config
3.0.0-next.8将配置读取改为通过@sveltejs/load-config完成。对应实现是 src/config.js 中的load_config():它从当前工作目录查找vite.config或svelte.config(traverse: false表示不向父目录遍历),加载结果中的config对象即被用于打包。这也意味着svelte.config.ts天然可用(详见第 7 节)。
3. CLI 实战:完整参数清单与用法
svelte-package的命令行帮助文本定义在 src/cli.js,全套参数如下:
| 参数 | 短选项 | 默认值 | 说明 |
|---|---|---|---|
--input <input> | -i | src/lib(或配置中的files.lib) | 输入目录 |
--output <output> | -o | dist | 输出目录 |
--preserve-output | -p | false | 打包前不删除输出目录 |
--types | -t | true | 是否生成类型声明 |
--watch | -w | false | 监听文件变化并增量重建 |
--tsconfig <path> | — | 自动向上搜索 | 指定 tsconfig/jsconfig 路径 |
--version | -v | — | 打印版本号 |
--help | -h | — | 打印帮助 |
典型用法(组件库项目内):
# 一键构建到 dist svelte-package # 指定输入输出并保留 dist 中已有的静态资源 svelte-package -i src/lib -o dist -p # 开发时增量构建 svelte-package -w # 指定 tsconfig(当多个 tsconfig 并存时) svelte-package --tsconfig tsconfig.build.json # 关闭类型声明生成(纯 JS 库提速) svelte-package --types false从 src/cli.js 可以看到选项与配置的合并逻辑:input取命令行参数,未提供时回退到config.files?.lib,最终默认src/lib;output默认dist。此外,若检测到config.package存在会直接报错——这是 2.0.0 移除的旧配置项,提示读者查阅迁移说明(见第 7 节)。
4. 别名解析:把$lib/#导入变成相对导入
这是 CHANGELOG 中出现频率最高的功能主题,贯穿 2.x 与 3.x:
3.0.0-next.3/3.0.0-next.5:feat: transform import aliases into relative imports in files;2.5.1~2.5.4:连续四轮修复,覆盖import/export * (as ...)、import/export name, { ... }等语法形态,并防止误替换(false-positive alias replacement);2.5.5:resolve aliases before transpiling for rewriteRelativeImportExtensions,保证别名解析在 TS 转译之前完成,让 TS 的扩展名重写也能作用于解析后的路径。
4.1 别名从哪来
src/index.js 的normalize_options展示了别名来源:options.config.alias中的配置别名之外,还会读取项目package.json的imports字段,把#开头的导入(含#foo/*通配形式)自动注册为别名。例如:
{ "imports": { "#utils/*": "./src/lib/utils/*", "#constants": "./src/lib/constants.js" } }这样源码里的import { x } from '#utils/math.js'在打包时会被解析为相对路径,天然支持 Node 的 subpath imports 约定。
4.2 替换算法
核心实现在 src/utils.js 的resolve_aliases:对每个 import 路径,依次与别名做前缀匹配,命中后用path.relative计算目标文件相对当前文件的相对路径,并确保以./开头。adjust_imports(同文件 L63-L107)则用正则覆盖了六种语法形态:
- 具名导入/导出
import { a } from '...'/export { a } from '...' - 命名空间
import * as All from '...'/export * as ns from '...' - 纯 re-export
export * from '...' - 动态导入
import('...') - 副作用导入
import '...'
测试用例 test/index.spec.js 明确验证了$lib/...、@/...等多种别名与上述语法形态的组合,是排查别名问题的第一手参考。
5. server-only 文件保护与包校验器
3.0.0-next.2/3.0.0-next.5新增能力:warn when using a .server. file or file inside a server directory without importing a server-only module。这是为"在 SvelteKit 应用内使用组件库"设计的防护。
5.1 判定规则
src/validate.js 中定义:文件名包含.server.,或位于server/目录下的文件,被视为 server-only;如果该文件(或其传递可达的相对导入链)没有导入$app/server或$app/env/private(这两个模块在客户端导入时会抛错),就输出警告。传递性检查由reaches_guard_import(同文件 L120-L140)配合resolve_relative_import完成,遍历整个相对导入图。
5.2 其他内置校验
validate()(src/validate.js)还会检查并给出黄色警告:
- 使用
$app/env但目标用户可能不基于 SvelteKit —— 建议改用esm-env; - 使用
import.meta.env(仅 Vite 应用可用)—— 建议改用esm-env; - 使用了
$app/导入或@sveltejs/kit,却未在dependencies/peerDependencies声明@sveltejs/kit; - 包含 Svelte 文件却未声明
svelte依赖; - 缺少
exports字段、Svelte 文件缺少svelte导出条件、pkg.svelte字段与exports不一致。
validate()本身不是build()的硬失败条件——src/index.js 在do_build完成后调用validate(),仅打印警告,避免 watch 模式下因告警而中断开发。
6. 类型声明生成与 TypeScript 转译
6.1emit_dts:基于 svelte2tsx 的声明产出
--types默认开启(true)。声明生成走 src/typescript.js 的emit_dts:调用svelte2tsx的emitDts,把.d.ts写入临时目录,再经别名解析(resolve_aliases)与声明 map 路径修正后拷贝到输出目录。有一个细节值得注意:svelte_dep从peerDependencies/dependencies读取后,会用semver.intersects判断是否兼容 Svelte 3,从而在svelte-shims.d.ts与svelte-shims-v4.d.ts之间选择(对应 2.2.0 的use Svelte 4 typings when packaging特性)。遇到"latest"、"next"等非 semver 版本串时,2.3.12的修复保证了不崩溃(回退为按 Svelte 4+ 处理)。
6.2 手写声明优先
emit_dts会跳过与源码中手写.d.ts冲突的文件并给出提示("Using $lib/xxx instead of generated .d.ts file")。因此,对需要精细控制公开类型的模块,直接提供手写.d.ts是受支持的做法。
6.3 TS → JS 转译
transpile_ts(src/typescript.js)使用 TypeScript 的transpileModule,并强制module: ESNext、moduleResolution: NodeNext。注释中说明这是为了解决NodeNext在transpileModule下被误判为 CommonJS 的已知问题(2.2.3的overwrite nodenext option when transpiling正是该修复)。若rewriteRelativeImportExtensions开启,还会通过自定义 transformer 把import.meta.glob('./*.ts')之类的相对 glob 中的.ts重写为.js,同时处理字符串字面量与模板字符串两种形态。
6.4 tsconfig 的查找与指定
- 未指定时,
load_tsconfig(src/typescript.js)从文件所在目录逐级向上查找最近的tsconfig.json/jsconfig.json,并带缓存; 2.3.0起可通过--tsconfig(或编程 API 的tsconfig选项)显式指定;3.0.0-next.4/3.0.0-next.5修复了"tsconfig 位于 package root 上方时也能正确生成声明"的问题(emit declarations when the tsconfig lives above the package root)——对应测试可在 test/index.spec.js 的 fixtures(如typescript-esnext、typescript-nodenext)中看到端倪。
6.5 扩展名重写:rewriteRelativeImportExtensions
2.5.6修复了 Svelte 文件中相对导入.ts → .js的重写。实现上是 src/utils.js 的resolve_ts_endings:对以./或../开头、以.ts结尾的导入路径统一替换为.js。在 Svelte 5 中<script lang="ts">原生可用,因此strip_lang_tags(同文件 L115-L128)会保留 Svelte 5 下的ts标签,同时保留application/ld+json等type="application/..."属性(对应1.0.0-next.4/next.5的修复历史)。
7. 配置读取与 Svelte 2.x 遗留项
7.1 支持svelte.config.ts
2.4.0起支持svelte.config.ts,CHANGELOG 附带了重要提示:运行环境必须支持导入 TS 文件。在 Node.js 中,Node 22.6.0+ 需要--experimental-strip-types标志,Node 23.6.0+ 无需标志即可直接使用。这与第 2 节"要求 Node 22+"相互呼应。
7.2 可用的配置项
从 src/types.d.ts 的Options.config可以看出svelte-package实际消费的字段:
| 配置项 | 类型 | 说明 |
|---|---|---|
alias | Record<string, string> | 路径别名,配合第 4 节的相对化转换 |
extensions | string[] | 视为 Svelte 组件的扩展名,默认['.svelte'] |
outDir | string | 临时输出目录,默认.svelte-kit(最终产物仍到dist) |
preprocess | PreprocessorGroup | 打包前对 Svelte 文件执行的预处理(与vitePreprocess等配合) |
files.lib | string(已废弃) | 旧版输入目录配置 |
7.3 2.0.0 的破坏性变更
2.0.0移除了package.json的生成能力与svelte.config.js中的package配置项,输出目录固定为dist。因此现在不推荐再写config.package(CLI 会直接报错并提示迁移),打包用的package.json元数据(exports、svelte条件等)完全由你在项目根目录自行维护。
8. 构建与监听:流水线视角
8.1 一次性构建(build)
src/index.js 的do_build展示了完整流水线:
normalize_options:解析输入/输出/临时目录、扩展名、别名、tsconfig;- 校验输入目录存在,清空并重建临时目录;
scan遍历输入目录全部文件(见 src/utils.js 的scan/analyze,dest规则:.svelte保持、.d.ts原样、其余.ts变.js);- 若
types开启,先emit_dts生成声明; - 逐文件
process_file:预处理 →resolve_aliases→ TS 转译/扩展名重写 → 写入; - 除非
preserve_output,否则删除dist后整体拷贝临时目录,输出形如src/lib -> dist的绿色日志。
--preserve-output(2.5.0新增)对应 src/index.js:跳过输出目录的整目录删除,便于把静态资源预置在dist中。测试 test/index.spec.js 演示了先往dist/assets写入文件再以preserve_output: true打包,产物中该文件得以保留。
8.2 监听模式(watch)
watch(src/index.js)基于chokidar(当前依赖chokidar@5,对应2.5.7的升级):
- 文件删除时同步删除
dist中对应产物及关联的.d.ts/.d.mts/.d.cts,并清理空目录; add/change事件以 100ms 防抖批量重处理;tsconfig/jsconfig 变化会清空 tsconfig 缓存并全量重建声明;- 单文件处理出错不会中断监听(对应
2.2.2的崩溃修复); 2.2.1起清空dist被延后到构建成功之后,避免失败时破坏已有产物。
9. 发布质量与生态细节
CHANGELOG 中还沉淀了一批发布侧的工程实践,值得组件库作者借鉴:
- 软件来源证明(provenance):
2.3.3/2.3.4为发布启用 provenance,增强供应链可信度; - npm 可发现性:
2.3.2为包添加 keywords,方便 npm 搜索命中; - 仓库 URL 规范:
2.4.1在package.json的 repository 地址补上.git后缀; - 依赖完整性检查:
1.0.0-next.6起,若打包产物涉及 Svelte 但package.json未声明svelte依赖会发出警告;3.0.0-next.1将typescript声明为可选 peer dependency,使包在 strict node-linkers(如 pnpm 严格模式)下也能安装使用。
10. 写出可发布组件库的清单
结合第 5 节校验器与源码行为,一个合格的 Svelte 库package.json应满足:
{ "name": "my-svelte-lib", "svelte": "./dist/index.js", "exports": { ".": { "svelte": "./dist/index.js", "types": "./dist/index.d.ts", "default": "./dist/index.js" } }, "files": ["dist"], "peerDependencies": { "svelte": "^5.0.0" } }要点:
- 必须提供
exports字段,且包含svelte条件,否则工具链无法识别这是 Svelte 包; svelte字段指向的入口要与exports['.']中实际导出的文件一致(校验器会逐字核对);- 使用了
$app/导入或import.meta.env时要么声明对应依赖,要么改用esm-env这类跨打包器方案; - server-only 文件(文件名含
.server.或在server/目录)务必通过import '$app/server'建立客户端防护。
结语
从 2.x 到 3.0.0-next,@sveltejs/package的演进主线非常清晰:依赖瘦身(sade/kleur → Node 内置)、配置现代化(@sveltejs/load-config、svelte.config.ts)、别名与扩展名处理的健壮化,以及面向"组件库被 SvelteKit 应用消费"场景的 server-only 防护。理解这些机制的落脚点都在 packages/package/src 这套不过百行级的模块化实现中——对库作者而言,它就是一份可直接对照的行为规范;对希望深入 SvelteKit 工具链的开发者而言,也是一个极佳的精读范本。
- Web框架
- 后端
- 前端
【免费下载链接】kit
web development, streamlined
相关推荐
使用 @sveltejs/package 构建与发布 Svelte 组件库:SvelteKit 打包指南
使用 @sveltejs/package 构建与发布 Svelte 组件库:SvelteKit 打包指南 导读:本文围绕 SvelteKit 官方文档「Pack
Web框架后端前端Cosmic IDE:Android上的桌面级JVM开发环境完全指南
Cosmic IDE:Android上的桌面级JVM开发环境完全指南 你是否曾想过在手机上编写、编译和运行Java/Kotlin代码?Cosmic IDE正是为
MobileFace人脸检测完全指南:从YOLOV3到实时50fps的优化之路
MobileFace人脸检测完全指南:从YOLOV3到实时50fps的优化之路 MobileFace是一个专为移动设备设计的人脸识别解决方案,它集成了人脸检测、
Web框架后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考