Svelte 开源仓库贡献指南:本地构建、测试体系与 PR 全流程实践
本文基于 Svelte 仓库根目录的 CONTRIBUTING.md 展开,系统梳理在 Svelte monorepo 中参与贡献的完整链路:从环境安装、UMD 编译器构建,到 vitest 测试体系的命令细节、快照更新、类型检查与代码规范,再到 RFC/Changeset/PR 模板的治理流程。读完本文,你应当能够独立完成"克隆仓库 → 本地跑通构建与测试 → 提交符合维护者要求的 PR"这一全流程。
项目定位与贡献入口
Svelte 是一种构建 Web 应用的新方式:它是一个编译器,将声明式组件编译为高效的 JavaScript,并对 DOM 进行外科手术式的更新。这一点在 CONTRIBUTING.md 开篇即被明确,也是理解整个贡献体系的背景——贡献对象既包括编译器(packages/svelte/src/compiler),也包括运行时(packages/svelte/src/internal)。
不写代码也能参与贡献,官方给出的参与方式包括:
- 直接使用 Svelte 并对照 Getting Started 文档验证行为是否符合预期,发现问题就提 issue;
- 浏览 open issues(尤其是
good first issue标签),提供变通方案、追问澄清、建议标签,或协助 triage; - 找到想修复的问题后直接开 PR;
- 阅读官方教程,发现表述不清之处通过文档站的 "Edit this page" 入口提交修改;
- 关注社区 feature request 标签,认领想做的功能并开 PR。
官方也明确表示:如果不知道如何规划自己的贡献,可以在社区 Discord 频道中说明需求寻求帮助。
治理流程:RFC、Roadmap 与维护者会议
在动手之前,理解 Svelte 的决策机制能帮你把贡献投在最有价值的地方:
RFC(请求提案)
如果你打算为大型新特性或重大变更提出实现方案,需要先走 RFC 流程公开讨论,避免方案落空。AGENTS.md 对 AI 编码代理的要求里同样强调了这一点:大型变更应参照 PR 模板中的 RFC 链接。
Roadmap 与优先级
维护团队一次通常只推进一个主要方向,好处有二:一是能主动而非被动地聚焦取得进展;二是可以把相关联的 issue 和 PR 批量处理,确保实现对问题和用例的整体覆盖。因此,与当前 roadmap 对齐的 PR 和 RFC 更可能被快速 review。PR 在核心活跃仓库中也更快,边缘仓库的 PR 则可能等待批量处理。
维护者月度会议
维护者在每月最后一个周六开会。会议不公开,但每个被讨论的 issue 都会在 issue 下留言反馈结论。议程通常对齐 roadmap 项目;需要维护者共同讨论的大型 PR 可以提出加入议程,但不符合当前优先级的条目通常只能安排少量。
分诊(Triaging)
不写代码的高价值贡献方式就是 triage issue 和 PR:
- 当 issue 信息不足以解决问题时,主动追问细节;
- 标记过时或应当关闭的 issue;
- 要求 PR 提供测试计划、参与代码 review。
Bug 报告规范
Svelte 使用 GitHub Issues 作为公开 bug 跟踪渠道。提 issue 前先看是否已有同类报告;确认是新的未报告 bug 再提交 bug report。
官方对 issue 的硬性要求(来自 CONTRIBUTING.md "Reporting new issues" 一节):
- 必须填写 issue 模板——这一步被特别强调为"非常重要"。不填模板可能导致 issue 无法被及时处理,这不是针对个人的态度问题;可以在补齐模板要求的信息后重新开一个新 issue。
- 一个 issue 只报告一个 bug。
- 提供复现步骤:列出复现所需的全部步骤,让阅读者能以最小代价复现;条件允许时使用官方 REPL 创建复现案例。
使用 Svelte 过程中的疑问则建议直接到社区 Discord 提问,而不是提 issue;希望推动的功能实现应使用 feature request 模板单独提 issue。
本地开发环境搭建
安装依赖
仓库要求先安装 pnpm(注意:CONTRIBUTING 原文此处为外部链接,遵循本文规范不再输出)。从 package.json 可以看到具体的版本约束:
{
"packageManager": "pnpm@10.33.4",
"engines": {
"pnpm": ">=9.0.0"
}
}
即 pnpm 最低要求 9.x,仓库锁定 pnpm 10.33.4(packageManager 字段供 corepack 等工具直接消费)。克隆仓库后在根目录执行:
pnpm install
这是 pnpm workspace 结构,pnpm-workspace.yaml 声明了两个 workspace 成员:
packages:
- 'packages/*'
- 'playgrounds/*'
同时该文件配置了 minimumReleaseAge: 2880 并排除了 @sveltejs/*、svelte、esrap、devalue 等自有/兄弟包,即第三方依赖需发布满 2880 分钟(2 天)才可安装,这是 Svelte 系仓库抵御供应链投毒的机制,属于理解锁文件更新行为时的必要背景。
构建 svelte/compiler
按 CONTRIBUTING.md 的说法,构建 svelte/compiler 的 UMD 版本只对 CommonJS 消费方或浏览器内使用是必要的,在 packages/svelte 目录下运行 pnpm build;源码改动时自动重建则运行 pnpm dev。
对照 packages/svelte/package.json 中两个脚本的实际定义:
"build": "rollup -c && pnpm generate && node scripts/check-treeshakeability.js",
"dev": "node scripts/process-messages -w & rollup -cw",
从脚本定义可以看出 pnpm build 实际是三段流水线:
rollup -c—— 打包发布产物;pnpm generate—— 即node scripts/process-messages && node ./scripts/generate-types.js && pnpm generate:browser-support,重新处理编译器诊断消息、生成 TypeScript 类型与浏览器支持数据;node scripts/check-treeshakeability.js—— 校验产物可被 tree-shake,防止运行时打包意外变大。
pnpm dev 则是并行监听模式:process-messages -w 监听诊断消息变更,rollup -cw 监听源码变更并热重建。
分支创建
Fork 仓库后从 main 分支创建你的工作分支。所有 PR 最终也必须指向 main——这与 .changeset/config.json 中的 "baseBranch": "main" 相互印证。
测试体系深入解析
这是贡献流程中最实操、也最容易踩坑的部分。
前置条件与运行命令
测试前必须先通过 playwright 安装 Chromium:
pnpm playwright install chromium
常用命令(均针对 CONTRIBUTING.md 原文的完整继承):
# 跑全量测试
pnpm test
# 只跑某一个测试套件
pnpm test validator
# 在某个套件内过滤测试
pnpm test validator -t a11y-alt-text
CONTRIBUTING.md 还提到一种非惯用但更彻底的过滤方式:
FILTER=<test-name> pnpm test <suite-name>
原文称之为 "Choose your fighter":它不是跳过其他测试,而是直接移除其他测试,结果更快更精简。这一点有源码级依据——packages/svelte/tests/suite.ts 的注释与实现:
/**
* To filter tests, run one of these:
*
* FILTER=my-test pnpm test (runs only the 'my-test' test)
* FILTER=/feature/ pnpm test (runs all tests matching /feature/)
*/
const filter = process.env.FILTER
? new RegExp(
process.env.FILTER.startsWith('/')
? process.env.FILTER.slice(1, -1).replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
: `^${process.env.FILTER.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}$`
)
: /./;
即 FILTER 支持精确匹配(自动锚定首尾)和 /正则/ 两种形式。注意 vitest 的 -t 参数做的是"跳过",而 FILTER 做的是"不注册",这正是官方推荐场景化选择的由来。
测试目录结构
CONTRIBUTING.md 说明:所有测试位于 /tests 目录,测试样例存放在 /tests/xxx/samples 文件夹中。在本仓库的实际路径中,这对应 packages/svelte/tests/ 下的多个套件目录,例如 validator、compiler-errors、css、hydration、runtime-runes、server-side-rendering、snapshot 等;每个样例是一个独立子目录(.svelte 组件 + 期望输出/_config.js)。
suite.ts 揭示了样例的加载机制:for_each_dir 遍历 samples/ 下每个目录,读取可选的 _config.js(支持 skip、solo、timeout 字段),目录名需通过 FILTER 正则才会注册为测试;若某目录只剩 _output/_actual.json 残留物(切分支遗留)则自动跳过。
vitest 层面的入口配置见 vitest.config.js:
include: [
'packages/svelte/**/*.test.ts',
'packages/svelte/tests/*/test.ts',
'packages/svelte/tests/runtime-browser/test-ssr.ts'
]
也就是说"套件"的入口就是各套件目录下的 test.ts,这就是 pnpm test validator 能定位到 packages/svelte/tests/validator/test.ts 的原因。该配置还包含一个 svelte 别名解析器:根据导入方路径中是否含 _output/server 决定解析到 server 端还是 browser 端导出,保证同一样例可同时覆盖客户端/服务端双端行为。
快照(snapshot)更新
snapshot、parser 等套件断言生成输出与已有快照一致。当编译器输出变化(例如你改进了代码生成)时,按 CONTRIBUTING.md 的说明更新快照:
UPDATE_SNAPSHOTS=true pnpm test
测试计划的写法
一个合格的测试计划应包含:你实际执行的命令及其输出;若 PR 涉及 UI,附上截图或视频。另外,若改动了 API,必须同步更新文档。
packages/svelte/tests/README.md 还记录了本套测试体系相对旧版的一些已知行为差异,例如:JSDOM 中属性变更不再同步反映(运行时在 tick 之后更新 DOM,许多测试需要额外 await Promise.resolve())、列表插入顺序改为从后往前(更快)、CSS 不再压缩而是注释掉未使用样式等。写新样例前值得一读,能少走弯路。
类型检查与代码规范
Typechecking
在 packages/svelte 内运行:
pnpm check # 类型检查
pnpm check:watch # watch 模式
从 packages/svelte/package.json 可以看到 pnpm check 实际执行的是三段串联的 tsc:
"check": "tsc --project tsconfig.runtime.json && tsc && cd ./tests/types && tsc"
分别覆盖运行时类型(tsconfig.runtime.json)、编译器主体类型、以及 packages/svelte/tests/types/ 下的公共类型断言测试(该目录含 snippet.ts、store.ts、component.ts 等对发布类型签名的用法级验证)。根目录的 pnpm check 会先执行 pnpm build 再对全部 workspace 递归 check(见 package.json)。
风格检查
CONTRIBUTING.md 说明 ESLint 会捕获大部分风格问题,运行 pnpm lint 查看状态。对照根 package.json 的定义,pnpm lint = eslint && prettier --check .,即ESLint + Prettier 双重校验。
值得注意的规则细节(来自 eslint.config.js):
no-console为error,源码中禁止遗留 console 调用;lube/svelte-naming-convention为error,从工具链层面强化命名约定;- 自定义规则
no_compiler_imports(eslint.config.js)禁止运行时代码 import 编译器代码(包括类型导入),防止编译器意外被打进运行时 bundle,也阻止 Node 环境类型泄漏进浏览器代码。
Prettier 侧的配置见 .prettierrc:useTabs: true、singleQuote: true、printWidth: 100、无尾逗号,并启用 prettier-plugin-svelte 插件处理 .svelte 文件。
命名约定
CONTRIBUTING.md 明确了两条核心命名约定:
snake_case:内部变量名与内部方法;camelCase:公共(对外 API)变量名与公共方法。
这条约定贯穿整个编译器与运行时源码(可从 packages/svelte/src/compiler/ 与 packages/svelte/src/internal/ 的文件命名直接观察到),新贡献代码保持一致即可。
类型生成(Generating Types)
CONTRIBUTING.md 指出:类型是从源码自动生成的,但生成结果会 checked in 仓库以防意外变更溜入。重新生成命令:
pnpm generate:types
对应 packages/svelte/package.json 中的定义:
"generate:types": "node ./scripts/generate-types.js && tsc -p tsconfig.generated.json"
即先由 packages/svelte/scripts/generate-types.js 生成类型产物,再用 packages/svelte/tsconfig.generated.json 做一致性编译。如果你在 PR 中修改了 src 下的 JSDoc 类型标注,提交前务必跑一次该命令并确认 diff 符合预期,否则类型产物与源码不同步会导致 CI 或 review 失败。
提交 Pull Request 的完整检查单
变更提案原则
- 尚未决定开 PR 的新功能/增强需求,可以先用 feature 模板提 issue 讨论;
- 纯 bug 修复可以直接提 PR,但仍建议先提 issue 说明要修复什么(即使修复方案不被采纳,issue 记录也有价值);
- 小 PR 更容易被 review、也更容易被合并。
提交前检查项
CONTRIBUTING.md 列出的三条硬性要求:
- 在 PR 描述中写明测试计划,并确认已测试你的变更;
- 代码通过 lint(
pnpm lint); - 测试全部通过(
pnpm test)。
仓库侧的 PR 模板(.github/PULL_REQUEST_TEMPLATE.md)把上述要求进一步细化为勾选清单,补充了几条关键规则:
- PR 标题以
feat:、fix:、chore:、docs:前缀开头; - 理想情况下包含"没有该 PR 会失败、有该 PR 会通过"的测试;
- 若改动落在
packages/svelte/src内,必须添加 changeset(npx changeset); - 必须运行
pnpm test与pnpm lint。
这与 CONTRIBUTING.md 原文中"若变更应导致版本号提升,在仓库根目录运行 npx changeset 并选择相应包"的要求完全一致。changeset 的机制配置见 .changeset/config.json:baseBranch 为 main,ignore 字段限定版本提升只作用于 @sveltejs/* 与 svelte 包;目录中现存的 .md 文件(如 calm-events-cleanup.md,内容为 'svelte': patch + 一句变更摘要)就是待发布变更的最小实例,可作为你书写 changeset 的格式参照。
Breaking changes 模板
引入破坏性变更时,PR 描述中必须填写 CONTRIBUTING.md 给出的固定模板:
### New breaking change here
- **Who does this affect**:
- **How to migrate**:
- **Why make this breaking change**:
- **Severity (number of people affected x effort)**:
四项分别回答:影响谁、如何迁移、为什么必须破坏、严重度(影响面 × 迁移成本)。这个模板的价值在于让维护者在合并前就能评估生态冲击。
手动验证他人(或自己)的 PR
想在另一个 pnpm 项目中手动测试某个 PR,可在该项目中执行(branch-name 替换为实际分支):
pnpm add -D "github:sveltejs/svelte#path:packages/svelte&branch-name"
这利用了 pnpm 的 github 依赖 + 子路径语法,直接把 packages/svelte 子包装进下游项目做集成验证,是 review 阶段非常实用的手段。
面向 AI 编码代理的补充约定
AGENTS.md 专门为在此 monorepo 中工作的 AI 编码代理立规:必须同时阅读并遵循 CONTRIBUTING.md;提交 PR 前必须阅读 PULL_REQUEST_TEMPLATE.md 并正确填写;未运行完整测试套件不得提交 PR。如果你用 AI 辅助参与本仓库贡献,把这三条作为硬性门禁即可与人类贡献者流程对齐。
License 与提问渠道
向 Svelte 提交贡献即表示你同意:你的贡献将以该仓库的 MIT 许可证(对应 LICENSE.md)发布。
关于流程本身、如何推进等问题,官方建议到社区 Discord 的 #contributing 频道提问。
小结:一条可执行的最小贡献路径
结合上述所有环节,一条经过仓库证据核对的最小可行贡献路径是:
pnpm install # 根目录,pnpm >= 9(仓库锁定 10.x)
pnpm playwright install chromium # 测试前置
pnpm test # 全量测试
pnpm lint # eslint + prettier 校验
cd packages/svelte
pnpm build # rollup 构建 + 消息/类型/浏览器支持生成 + tree-shake 校验
pnpm check # 三段 tsc 类型检查
pnpm generate:types # 若改动涉及类型标注
然后:从 main 开分支 → 小步提交 → npx changeset(涉及 packages/svelte/src 时)→ 按 PR 模板 填写描述与测试计划 → 指向 main 提交 PR。对于大型设计,先走 RFC;对齐 roadmap 的改动会获得最快的响应。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00