Skip to content

feat: add --incremental and --tsgo flags to @sveltejs/package#15467

Open
datstarkey wants to merge 2 commits intosveltejs:mainfrom
datstarkey:feat/package-incremental-tsgo
Open

feat: add --incremental and --tsgo flags to @sveltejs/package#15467
datstarkey wants to merge 2 commits intosveltejs:mainfrom
datstarkey:feat/package-incremental-tsgo

Conversation

@datstarkey
Copy link

Summary

Adds --incremental and --tsgo CLI flags to svelte-package for faster declaration emit. This adapts the write-to-disk + shell-out architecture from svelte-check's incremental mode (language-tools PR #2932) for declaration emit in @sveltejs/package.

When either flag is set, the new pipeline replaces the emitDts() call with:

  1. Pre-transpile .svelte files to .ts on disk via svelte2tsx() with manifest-based caching (mtime+size)
  2. Generate overlay tsconfig with declaration: true, emitDeclarationOnly: true
  3. Spawn tsc or tsgo as a child process to emit .d.ts files
  4. Post-process emitted .d.ts files: resolve $lib aliases, fix sourcemap paths, handle hand-written .d.ts precedence

The default path (no flags) is completely unchanged — all existing tests pass unmodified.

How the flags interact

Flags Compiler Caching Effect
(none) svelte2tsx emitDts() None Current behavior, unchanged
--incremental tsc manifest + .tsbuildinfo 2nd+ runs skip unchanged files
--tsgo tsgo manifest only Every run faster (Go compiler)
--incremental --tsgo tsgo manifest + .tsbuildinfo Maximum speed

Benchmarks

Tested on a 264-component Svelte library (420 total files):

Command Cold Warm Speedup
svelte-package (baseline) 7.2s 7.2s 1x
--incremental 7.2s 3.1s 2.3x
--tsgo 3.7s 1.8s 2x / 4x
--incremental --tsgo 2.5s 1.6s 2.9x / 4.5x

Changes

  • New: packages/package/src/emit-dts-incremental.js — core pipeline (~500 lines)
  • Modified: cli.js (flags), types.d.ts (types), index.js (routing), typescript.js (extracted shared resolve_svelte_shims helper)
  • Bumped: svelte2tsx to ~0.7.51 for rewriteExternalImports and emitJsDoc support
  • Added: @typescript/native-preview as optional peer dependency

Known limitations

  • The .d.ts output from the incremental path may have minor differences from the default path (whitespace from tsc formatting, slightly less precise types for edge cases in dts mode). Functionally equivalent.
  • Expected harmless errors from svelte2tsx dts-mode intermediate files are filtered and suppressed.

Test plan

  • All 19 existing @sveltejs/package tests pass (default path unchanged)
  • pnpm run lint passes
  • pnpm run check passes (0 errors)
  • pnpm -F @sveltejs/kit test:unit passes
  • pnpm test:others passes
  • Manual test: --incremental produces equivalent output on typescript-esnext fixture
  • Manual test: --tsgo fails gracefully when @typescript/native-preview not installed
  • Manual test: warm cache hits work correctly on second run

Add write-to-disk + shell-out pipeline for declaration emit, adapted from
the approach used in svelte-check's incremental mode (PR sveltejs#2932).

When `--incremental` or `--tsgo` is passed, svelte-package:
1. Pre-transpiles .svelte files to .ts via svelte2tsx() with manifest caching
2. Generates an overlay tsconfig with declaration emit settings
3. Spawns tsc (or tsgo from @typescript/native-preview) as a child process
4. Post-processes emitted .d.ts files (alias resolution, sourcemap fixup)

The default path (no flags) is completely unchanged.

Benchmarks on a 264-component Svelte library:
- Baseline (emitDts):     ~7.2s every run
- --incremental warm:     ~3.1s (2.3x faster)
- --tsgo cold:            ~3.7s (2x faster)
- --incremental --tsgo:   ~1.6s (4.5x faster)

Also bumps svelte2tsx to ~0.7.51 for rewriteExternalImports and emitJsDoc
support, and adds @typescript/native-preview as an optional peer dependency.
@changeset-bot
Copy link

changeset-bot bot commented Mar 2, 2026

⚠️ No Changeset found

Latest commit: 495822c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

The optional peer dependency caused lockfile sync issues in CI.
The --tsgo flag already handles the missing package gracefully
with a clear error message directing users to install it.
files,
cwd
) {
if (!fs.existsSync(declarations_dir)) return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale declaration files from deleted source files persist in the output when using incremental declaration emit.

Fix on Vercel


emitted.push(file.name);
} catch (e) {
console.error(`Error transpiling ${file.name}: ${/** @type {Error} */ (e).message}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a Svelte file fails to transpile via svelte2tsx, stale generated files from previous successful runs are not cleaned up, causing tsc to produce outdated type declarations.

Fix on Vercel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant