Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/scripts/upgrade-deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,50 @@ async function updateVitestVersionConstant(vitestVersion: string): Promise<void>
console.log('Updated packages/cli/src/utils/constants.ts');
}

// ============ Update tsdown-migrate version ============
// The current RC adds non-TTY support while it still targets tsdown 0.22.14.
// Keep that RC until the stable tsdown version advances. At that point, require
// tsdown-migrate to have the same stable version and replace the RC pin.
async function updateTsdownMigrateVersion(
tsdownVersion: string,
stableMigrateVersion: string,
): Promise<void> {
const tsdownChange = changes.get('tsdown');
if (!tsdownChange) {
throw new Error('The tsdown catalog update did not record a version');
}

const filePath = path.join(ROOT, 'packages/cli/src/utils/constants.ts');
const content = fs.readFileSync(filePath, 'utf8');
const pattern = /export const TSDOWN_MIGRATE_VERSION = '([\d.]+(?:-[\w.]+)?)';/;
let currentMigrateVersion: string | undefined;
const tsdownAdvanced = tsdownChange.old !== tsdownChange.new;

if (tsdownAdvanced && stableMigrateVersion !== tsdownVersion) {
throw new Error(
`Stable tsdown advanced to ${tsdownVersion}, but stable tsdown-migrate is ` +
`${stableMigrateVersion}. Update their compatibility before the dependency upgrade.`,
);
}

const updated = content.replace(pattern, (_match: string, captured: string) => {
currentMigrateVersion = captured;
const nextMigrateVersion = tsdownAdvanced ? stableMigrateVersion : captured;
return `export const TSDOWN_MIGRATE_VERSION = '${nextMigrateVersion}';`;
});
if (currentMigrateVersion === undefined) {
throw new Error(
`Failed to match TSDOWN_MIGRATE_VERSION in ${filePath} — the pattern ${pattern} is stale, ` +
`please update it in .github/scripts/upgrade-deps.ts`,
);
}

const nextMigrateVersion = tsdownAdvanced ? stableMigrateVersion : currentMigrateVersion;
fs.writeFileSync(filePath, updated);
recordChange('tsdown-migrate', currentMigrateVersion, nextMigrateVersion);
console.log('Updated packages/cli/src/utils/constants.ts');
}

// ============ Update README.md manual-migration vitest pins ============
// The manual-migration guide pins `vitest` to an exact version in three places —
// the npm/Bun `overrides` block, the pnpm-workspace `overrides` block, and the
Expand Down Expand Up @@ -519,6 +563,7 @@ console.log('Fetching latest versions…');
const [
vitestVersion,
tsdownVersion,
stableTsdownMigrateVersion,
lightningcssVersion,
devtoolsVersion,
oxcNodeCliVersion,
Expand All @@ -534,6 +579,7 @@ const [
] = await Promise.all([
getLatestNpmVersion('vitest'),
getLatestNpmVersion('tsdown'),
getLatestNpmVersion('tsdown-migrate'),
// Mirror exactly what the bundled @tsdown/css depends on.
getNpmDependencyRange('@tsdown/css', 'lightningcss'),
getLatestNpmVersion('@vitejs/devtools'),
Expand All @@ -551,6 +597,7 @@ const [

console.log(`vitest: ${vitestVersion}`);
console.log(`tsdown: ${tsdownVersion}`);
console.log(`tsdown-migrate (stable): ${stableTsdownMigrateVersion}`);
console.log(`lightningcss (from @tsdown/css): ${lightningcssVersion}`);
console.log(`@vitejs/devtools: ${devtoolsVersion}`);
console.log(`@oxc-node/cli: ${oxcNodeCliVersion}`);
Expand Down Expand Up @@ -580,6 +627,7 @@ await updatePnpmWorkspace({
oxcParser: oxcParserVersion,
oxcTransform: oxcTransformVersion,
});
await updateTsdownMigrateVersion(tsdownVersion, stableTsdownMigrateVersion);
await updateVitestVersionConstant(vitestVersion);
await updateReadmeVitestPins(vitestVersion);
await updateCorePackage(devtoolsVersion);
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ jobs:
vp run lint
vp run test:run
npx tsc --noEmit
- name: decoders
node-version: 24
command: |
vp pack
vp test
- name: vite-vue-vercel
node-version: 24
command: |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "migration-from-tsup",
"scripts": {
"build": "tsup --config tsup.config.ts"
},
"devDependencies": {
"tsup": "^8.5.0",
"vite": "^7.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[[case]]
name = "migration_from_tsup_success"
vp = "local"
env = { VP_CLI_BIN = "./tsdown-migrate-stub.mjs" }
steps = [
{ argv = ["vpt", "chmod", "+x", "tsdown-migrate-stub.mjs"], comment = "stub tsdown-migrate so the migration stays offline", continue-on-failure = true },
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "tsup config should migrate automatically", continue-on-failure = true },
{ argv = ["vpt", "stat-file", "tsup.config.ts", "--assert-not", "file"], comment = "the original tsup config is removed", continue-on-failure = true },
{ argv = ["vpt", "print-file", "tsdown.config.ts"], comment = "the converted config uses vite-plus pack", continue-on-failure = true },
{ argv = ["vpt", "print-file", "vite.config.ts"], comment = "the converted config is connected to vite.config.ts", continue-on-failure = true },
{ argv = ["vpt", "print-file", "package.json"], comment = "tsup is removed and its script uses vp pack", continue-on-failure = true },
]

[[case]]
name = "migration_from_tsup_failure"
vp = "local"
env = { VP_CLI_BIN = "./tsdown-migrate-stub.mjs", TSDOWN_MIGRATE_STUB_FAIL = "1" }
steps = [
{ argv = ["vpt", "chmod", "+x", "tsdown-migrate-stub.mjs"], comment = "stub a tsdown-migrate failure", continue-on-failure = true },
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "a failed automatic migration should show manual options", continue-on-failure = true },
{ argv = ["vpt", "stat-file", "tsup.config.ts", "--assert", "file"], comment = "the original tsup config is preserved", continue-on-failure = true },
{ argv = ["vpt", "stat-file", "tsdown.config.ts", "--assert-not", "file"], comment = "no converted config is left behind", continue-on-failure = true },
{ argv = ["vpt", "print-file", "package.json"], comment = "the tsup dependency and script are preserved", continue-on-failure = true },
]

[[case]]
name = "migration_from_tsup_config_collision"
vp = "local"
steps = [
{ argv = ["vpt", "write-file", "tsdown.config.ts", "export default { existing: true };\n"], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "an existing tsdown config should stop automatic migration before it overwrites files", continue-on-failure = true },
{ argv = ["vpt", "print-file", "tsup.config.ts"], comment = "the original tsup config is unchanged" },
{ argv = ["vpt", "print-file", "tsdown.config.ts"], comment = "the existing tsdown config is unchanged" },
{ argv = ["vpt", "print-file", "package.json"], comment = "the tsup dependency and script are unchanged" },
]

[[case]]
name = "migration_from_tsup_inline_config_collision"
vp = "local"
steps = [
{ argv = ["vpt", "rm", "tsup.config.ts"], snapshot = false },
{ argv = ["vpt", "json-edit", "package.json", "scripts.build", "tsup"], snapshot = false },
{ argv = ["vpt", "json-edit", "package.json", "tsup", '{"entry":["src/index.ts"]}'], snapshot = false },
{ argv = ["vpt", "json-edit", "package.json", "tsdown", '{"entry":["src/existing.ts"]}'], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "an existing inline tsdown config should stop automatic migration", continue-on-failure = true },
{ argv = ["vpt", "print-file", "package.json"], comment = "both inline configs are unchanged" },
]

[[case]]
name = "migration_from_tsup_inline_config"
vp = "local"
steps = [
{ argv = ["vpt", "rm", "tsup.config.ts"], snapshot = false },
{ argv = ["vpt", "json-edit", "package.json", "scripts.build", "tsup"], snapshot = false },
{ argv = ["vpt", "json-edit", "package.json", "tsup", '{"entry":["src/index.ts"]}'], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "an inline tsup config should stop automatic migration", continue-on-failure = true },
{ argv = ["vpt", "print-file", "package.json"], comment = "the inline tsup config is unchanged" },
]

[[case]]
name = "migration_from_tsup_custom_config"
vp = "local"
steps = [
{ argv = ["vpt", "mkdir", "-p", "configs"], snapshot = false },
{ argv = ["vpt", "write-file", "configs/legacy.ts", "export default {};\n"], snapshot = false },
{ argv = ["vpt", "json-edit", "package.json", "scripts.build", "tsup --config configs/legacy.ts"], snapshot = false },
{ argv = ["vpt", "json-edit", "package.json", "scripts.irregular", "tsup --config ././tsup.config.ts"], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "unsupported config paths should stop automatic migration before any files change", continue-on-failure = true },
{ argv = ["vpt", "print-file", "tsup.config.ts"], comment = "the standard config is unchanged" },
{ argv = ["vpt", "print-file", "configs/legacy.ts"], comment = "the custom config is unchanged" },
{ argv = ["vpt", "print-file", "package.json"], comment = "the unsupported scripts and tsup dependency are unchanged" },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# migration_from_tsup_config_collision

## `vpt write-file tsdown.config.ts 'export default { existing: true };
'`


## `vp migrate --no-interactive --no-hooks --no-agent --no-editor`

an existing tsdown config should stop automatic migration before it overwrites files

**Exit code:** 1

```
VITE+ - The Unified Toolchain for the Web

tsup configuration detected. Auto-migrating to tsdown...

Automatic tsup migration was skipped because these tsdown configs already exist:
tsdown.config.ts

Resolve this configuration conflict manually:
1. Merge the tsup and tsdown configurations into `pack` in `vite.config.*`.
2. Do not run `tsdown-migrate`. It can overwrite the existing tsdown configuration.

Use the tsdown migration skill for guidance:
https://github.com/rolldown/tsdown/blob/main/skills/tsdown-migrate/SKILL.md
Complete the tsup migration manually, then re-run `vp migrate`.
```

## `vpt print-file tsup.config.ts`

the original tsup config is unchanged

```
import { defineConfig } from 'tsup';

export default defineConfig({
entry: ['src/index.ts'],
dts: true,
format: ['esm', 'cjs'],
splitting: false,
});
```

## `vpt print-file tsdown.config.ts`

the existing tsdown config is unchanged

```
export default { existing: true };
```

## `vpt print-file package.json`

the tsup dependency and script are unchanged

```
{
"name": "migration-from-tsup",
"scripts": {
"build": "tsup --config tsup.config.ts"
},
"devDependencies": {
"tsup": "^8.5.0",
"vite": "^7.0.0"
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# migration_from_tsup_custom_config

## `vpt mkdir -p configs`


## `vpt write-file configs/legacy.ts 'export default {};
'`


## `vpt json-edit package.json scripts.build 'tsup --config configs/legacy.ts'`


## `vpt json-edit package.json scripts.irregular 'tsup --config ././tsup.config.ts'`


## `vp migrate --no-interactive --no-hooks --no-agent --no-editor`

unsupported config paths should stop automatic migration before any files change

**Exit code:** 1

```
VITE+ - The Unified Toolchain for the Web

tsup configuration detected. Auto-migrating to tsdown...

Automatic tsup migration was skipped because these scripts use configs that cannot be migrated automatically:
package.json#build -> configs/legacy.ts
package.json#irregular -> ././tsup.config.ts

Resolve these config paths manually:
1. Migrate each listed config into `pack` in `vite.config.*`.
2. Update each listed script.
3. Do not run `tsdown-migrate`. It cannot safely resolve these config paths.

Use the tsdown migration skill for guidance:
https://github.com/rolldown/tsdown/blob/main/skills/tsdown-migrate/SKILL.md
Complete the tsup migration manually, then re-run `vp migrate`.
```

## `vpt print-file tsup.config.ts`

the standard config is unchanged

```
import { defineConfig } from 'tsup';

export default defineConfig({
entry: ['src/index.ts'],
dts: true,
format: ['esm', 'cjs'],
splitting: false,
});
```

## `vpt print-file configs/legacy.ts`

the custom config is unchanged

```
export default {};
```

## `vpt print-file package.json`

the unsupported scripts and tsup dependency are unchanged

```
{
"devDependencies": {
"tsup": "^8.5.0",
"vite": "^7.0.0"
},
"name": "migration-from-tsup",
"scripts": {
"build": "tsup --config configs/legacy.ts",
"irregular": "tsup --config ././tsup.config.ts"
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# migration_from_tsup_failure

## `vpt chmod +x tsdown-migrate-stub.mjs`

stub a tsdown-migrate failure

```
```

## `vp migrate --no-interactive --no-hooks --no-agent --no-editor`

a failed automatic migration should show manual options

**Exit code:** 1

```
VITE+ - The Unified Toolchain for the Web

tsup configuration detected. Auto-migrating to tsdown...

Automatic tsup migration failed.

Choose one of these manual migration methods:
1. Run `vp dlx tsdown-migrate` in the project root.
2. Use the tsdown migration skill:
https://github.com/rolldown/tsdown/blob/main/skills/tsdown-migrate/SKILL.md

Complete the tsup migration manually, then re-run `vp migrate`.
```

## `vpt stat-file tsup.config.ts --assert file`

the original tsup config is preserved

```
tsup.config.ts: file
```

## `vpt stat-file tsdown.config.ts --assert-not file`

no converted config is left behind

```
tsdown.config.ts: missing
```

## `vpt print-file package.json`

the tsup dependency and script are preserved

```
{
"name": "migration-from-tsup",
"scripts": {
"build": "tsup --config tsup.config.ts"
},
"devDependencies": {
"tsup": "^8.5.0",
"vite": "^7.0.0"
}
}
```
Loading
Loading