Skip to content

Commit 6866db7

Browse files
committed
fix(pack): harden tsdown extension wiring and lightningcss version sync
- wireBundledTsdownExtensions: scan every emitted chunk (not just build-*.js) and assert the bundled ./tsdown-css.js is referenced, so a rolldown chunking change can't silently ship an unrewritten import. - upgrade-deps: match any lightningcss range value so a non-caret range from @tsdown/css can't poison the next run's pattern. - rfc: lightningcss is a core dependency, not an optional peer.
1 parent 0732169 commit 6866db7

3 files changed

Lines changed: 23 additions & 9 deletions

File tree

.github/scripts/upgrade-deps.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,9 @@ async function updatePnpmWorkspace(versions: PnpmWorkspaceVersions): Promise<voi
252252
// tsdown upgrade that bumps lightningcss is mirrored here.
253253
{
254254
name: 'lightningcss',
255-
pattern: /\n {2}lightningcss: (\^?[\d.]+(?:-[\w.]+)?)\n/,
255+
// Match any range value (not just `^x.y.z`) so the pattern can re-match
256+
// whatever `@tsdown/css` declares (`~`, `>=`, compound ranges) on the next run.
257+
pattern: /\n {2}lightningcss: ([^\n]+)\n/,
256258
replacement: `\n lightningcss: ${versions.lightningcss}\n`,
257259
newVersion: versions.lightningcss,
258260
},

packages/core/build.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -588,9 +588,11 @@ async function brandTsdown() {
588588
// top-level packages. See https://github.com/voidzero-dev/vite-plus/issues/1586
589589
async function wireBundledTsdownExtensions() {
590590
const tsdownDistDir = join(projectDir, 'dist/tsdown');
591-
const buildFiles = await glob(toPosixPath(join(tsdownDistDir, 'build-*.js')), { absolute: true });
592-
if (buildFiles.length === 0) {
593-
throw new Error('wireBundledTsdownExtensions: no build chunk found in dist/tsdown/');
591+
// Scan every emitted chunk, not just `build-*.js`: which chunk rolldown hoists
592+
// these call sites into depends on its chunking heuristics, so don't pin to one.
593+
const chunkFiles = await glob(toPosixPath(join(tsdownDistDir, '*.js')), { absolute: true });
594+
if (chunkFiles.length === 0) {
595+
throw new Error('wireBundledTsdownExtensions: no chunk found in dist/tsdown/');
594596
}
595597

596598
// Route `@tsdown/exe` and `@tsdown/css` to the bundled entries.
@@ -602,8 +604,12 @@ async function wireBundledTsdownExtensions() {
602604
// bundled), which resolves to core's own `lightningcss` dependency.
603605
let exeWired = false;
604606
let cssWired = false;
605-
for (const buildFile of buildFiles) {
606-
let content = await readFile(buildFile, 'utf-8');
607+
// The `import("@tsdown/css")` call site may already be deduped to the bundled
608+
// entry by rolldown; track whether the bundled load ends up referenced either
609+
// way so a silent miss (no rewrite and no dedup) fails the build.
610+
let cssLoadWired = false;
611+
for (const chunkFile of chunkFiles) {
612+
let content = await readFile(chunkFile, 'utf-8');
607613
let changed = false;
608614
if (content.includes('importWithError("@tsdown/exe")')) {
609615
content = content.replaceAll('importWithError("@tsdown/exe")', 'import("./tsdown-exe.js")');
@@ -619,8 +625,11 @@ async function wireBundledTsdownExtensions() {
619625
content = content.replaceAll('import("@tsdown/css")', 'import("./tsdown-css.js")');
620626
changed = true;
621627
}
628+
if (content.includes('import("./tsdown-css.js")')) {
629+
cssLoadWired = true;
630+
}
622631
if (changed) {
623-
await writeFile(buildFile, content);
632+
await writeFile(chunkFile, content);
624633
}
625634
}
626635
if (!exeWired) {
@@ -629,6 +638,9 @@ async function wireBundledTsdownExtensions() {
629638
if (!cssWired) {
630639
throw new Error('wireBundledTsdownExtensions: `pkgExists("@tsdown/css")` not found');
631640
}
641+
if (!cssLoadWired) {
642+
throw new Error('wireBundledTsdownExtensions: bundled `./tsdown-css.js` is never imported');
643+
}
632644
}
633645

634646
// Actually do nothing now, we will polish it in the future when `vitepress` is ready

rfcs/pack-command.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ These are distinct commands:
300300
- Ensures consistent tsdown version across all vite-plus users
301301
- Avoids version conflicts in monorepos
302302
- The core build process bundles JS, CJS deps, and types together
303-
- The extensions peer-depend on `tsdown`/`tsdown/internal`, which Vite+ does not expose as a top-level package, so bundling them is the only way they resolve (issue #1586). Only `lightningcss` (native) stays external as an optional peer.
303+
- The extensions peer-depend on `tsdown`/`tsdown/internal`, which Vite+ does not expose as a top-level package, so bundling them is the only way they resolve (issue #1586). Only `lightningcss` (native, cannot be bundled) stays external; it ships as a regular core dependency.
304304
305305
### 4. Category C Delegation
306306
@@ -404,7 +404,7 @@ This RFC documents an existing command with no breaking changes:
404404
- All existing `vp pack` options continue to work
405405
- The new `--exe` flag is purely additive
406406
- Config format in `vite.config.ts` is unchanged
407-
- Bundling `@tsdown/exe`/`@tsdown/css` is a strict improvement: projects that previously installed them keep working and no longer need to. CSS bundling now only requires the optional `lightningcss` peer (`vp add -D lightningcss`), which is loaded lazily with an actionable error when missing.
407+
- Bundling `@tsdown/exe`/`@tsdown/css` is a strict improvement: projects that previously installed them keep working and no longer need to. CSS bundling works out of the box, `lightningcss` is a core dependency that ships with the toolchain, so nothing extra needs installing.
408408
409409
## Exe Advanced Configuration
410410

0 commit comments

Comments
 (0)