@sveltejs/package 全解析:Svelte 组件库打包器从 2.x 到 3.x 的核心机制与实战指南
2026/9/21 19:00:29 网站建设 项目流程
  • Web框架
  • 后端
  • 前端

【免费下载链接】kit

web development, streamlined

项目地址:https://gitcode.com/gh_mirrors/kit/kit
点击查看免费下载

@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.03.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.43.0.0-next.5连续移除了sade(命令行解析库)与kleur(颜色输出库),改用 Node 内置能力。从 src/cli.js 可以看到,如今参数解析使用node:utilparseArgs,彩色输出使用styleText——这既减少了依赖树体积,也让包在 Node 22 下的行为更一致。

2.3 配置读取迁移到@sveltejs/load-config

3.0.0-next.8将配置读取改为通过@sveltejs/load-config完成。对应实现是 src/config.js 中的load_config():它从当前工作目录查找vite.configsvelte.configtraverse: false表示不向父目录遍历),加载结果中的config对象即被用于打包。这也意味着svelte.config.ts天然可用(详见第 7 节)。

3. CLI 实战:完整参数清单与用法

svelte-package的命令行帮助文本定义在 src/cli.js,全套参数如下:

参数短选项默认值说明
--input <input>-isrc/lib(或配置中的files.lib输入目录
--output <output>-odist输出目录
--preserve-output-pfalse打包前不删除输出目录
--types-ttrue是否生成类型声明
--watch-wfalse监听文件变化并增量重建
--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/liboutput默认dist。此外,若检测到config.package存在会直接报错——这是 2.0.0 移除的旧配置项,提示读者查阅迁移说明(见第 7 节)。

4. 别名解析:把$lib/#导入变成相对导入

这是 CHANGELOG 中出现频率最高的功能主题,贯穿 2.x 与 3.x:

  • 3.0.0-next.3/3.0.0-next.5feat: transform import aliases into relative imports in files
  • 2.5.12.5.4:连续四轮修复,覆盖import/export * (as ...)import/export name, { ... }等语法形态,并防止误替换(false-positive alias replacement);
  • 2.5.5resolve aliases before transpiling for rewriteRelativeImportExtensions,保证别名解析在 TS 转译之前完成,让 TS 的扩展名重写也能作用于解析后的路径。

4.1 别名从哪来

src/index.js 的normalize_options展示了别名来源:options.config.alias中的配置别名之外,还会读取项目package.jsonimports字段,把#开头的导入(含#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-exportexport * 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:调用svelte2tsxemitDts,把.d.ts写入临时目录,再经别名解析(resolve_aliases)与声明 map 路径修正后拷贝到输出目录。有一个细节值得注意:svelte_deppeerDependencies/dependencies读取后,会用semver.intersects判断是否兼容 Svelte 3,从而在svelte-shims.d.tssvelte-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: ESNextmoduleResolution: NodeNext。注释中说明这是为了解决NodeNexttranspileModule下被误判为 CommonJS 的已知问题(2.2.3overwrite 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-esnexttypescript-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+jsontype="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实际消费的字段:

配置项类型说明
aliasRecord<string, string>路径别名,配合第 4 节的相对化转换
extensionsstring[]视为 Svelte 组件的扩展名,默认['.svelte']
outDirstring临时输出目录,默认.svelte-kit(最终产物仍到dist
preprocessPreprocessorGroup打包前对 Svelte 文件执行的预处理(与vitePreprocess等配合)
files.libstring(已废弃)旧版输入目录配置

7.3 2.0.0 的破坏性变更

2.0.0移除了package.json的生成能力与svelte.config.js中的package配置项,输出目录固定为dist。因此现在不推荐再写config.package(CLI 会直接报错并提示迁移),打包用的package.json元数据(exportssvelte条件等)完全由你在项目根目录自行维护。

8. 构建与监听:流水线视角

8.1 一次性构建(build

src/index.js 的do_build展示了完整流水线:

  1. normalize_options:解析输入/输出/临时目录、扩展名、别名、tsconfig;
  2. 校验输入目录存在,清空并重建临时目录;
  3. scan遍历输入目录全部文件(见 src/utils.js 的scan/analyzedest规则:.svelte保持、.d.ts原样、其余.ts.js);
  4. types开启,先emit_dts生成声明;
  5. 逐文件process_file:预处理 →resolve_aliases→ TS 转译/扩展名重写 → 写入;
  6. 除非preserve_output,否则删除dist后整体拷贝临时目录,输出形如src/lib -> dist的绿色日志。

--preserve-output2.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.1package.json的 repository 地址补上.git后缀;
  • 依赖完整性检查1.0.0-next.6起,若打包产物涉及 Svelte 但package.json未声明svelte依赖会发出警告;3.0.0-next.1typescript声明为可选 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-configsvelte.config.ts)、别名与扩展名处理的健壮化,以及面向"组件库被 SvelteKit 应用消费"场景的 server-only 防护。理解这些机制的落脚点都在 packages/package/src 这套不过百行级的模块化实现中——对库作者而言,它就是一份可直接对照的行为规范;对希望深入 SvelteKit 工具链的开发者而言,也是一个极佳的精读范本。

  • Web框架
  • 后端
  • 前端

【免费下载链接】kit

web development, streamlined

项目地址:https://gitcode.com/gh_mirrors/kit/kit
点击查看免费下载
上一篇:告别版本混乱:nvm个性化Node.js版本管理指南
下一篇:现代Web应用中的动态进度可视化:ProgressBar.js深度解析与技术实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询