Skip to content

Speed up d.ts generation by batching entries into worker processes#34329

Open
kasperpeulen wants to merge 3 commits intonextfrom
claude/general-session-H6RfH
Open

Speed up d.ts generation by batching entries into worker processes#34329
kasperpeulen wants to merge 3 commits intonextfrom
claude/general-session-H6RfH

Conversation

@kasperpeulen
Copy link
Contributor

@kasperpeulen kasperpeulen commented Mar 26, 2026

Instead of spawning 27 separate processes (each loading rollup, typescript,
and creating a full TS program from scratch), batch entries into 4 worker
processes. Each worker processes entries sequentially, amortizing module
loading and benefiting from OS file cache warming. Workers run in parallel
for multi-core utilization. Includes retry logic for inter-entry
dependencies and 8GB memory per worker to prevent OOM.

Reduces core package d.ts generation from ~2.82min to ~1.57min (44% faster).

https://claude.ai/code/session_01DUhTmj7c91ao6ga2DJPrTB

Summary by CodeRabbit

  • Chores
    • Added development dependencies for enhanced TypeScript tooling and bundling capabilities.
    • Optimized type generation process for improved build performance and efficiency.

claude added 3 commits March 25, 2026 20:11
Instead of spawning 27 separate processes (each loading rollup, typescript,
and creating a full TS program from scratch), batch entries into 4 worker
processes. Each worker processes entries sequentially, amortizing module
loading and benefiting from OS file cache warming. Workers run in parallel
for multi-core utilization. Includes retry logic for inter-entry
dependencies and 8GB memory per worker to prevent OOM.

Reduces core package d.ts generation from ~2.82min to ~1.57min (44% faster).

https://claude.ai/code/session_01DUhTmj7c91ao6ga2DJPrTB
Use filesystem-based retry: after all batches complete, check which
entries are still missing d.ts output and retry them in a single batch.
This handles cross-batch dependencies (e.g. mocking-utils depends on
babel's d.ts) without fragile timing-based retries.

https://claude.ai/code/session_01DUhTmj7c91ao6ga2DJPrTB
…ster d.ts generation

Use rolldown (Rust-based bundler) and tsgo (Go-based TypeScript compiler) instead
of rollup + rollup-plugin-dts + tsc. tsgo compiles all entries in ~7s (vs ~10s per
entry with tsc), and rolldown bundles declarations natively. Total types generation
drops from ~2.7min to ~10s for the core package.

https://claude.ai/code/session_01DUhTmj7c91ao6ga2DJPrTB
@github-actions
Copy link
Contributor

github-actions bot commented Mar 26, 2026

Fails
🚫

PR is not labeled with one of: ["cleanup","BREAKING CHANGE","feature request","bug","documentation","maintenance","build","dependencies"]

🚫 PR title must be in the format of "Area: Summary", With both Area and Summary starting with a capital letter Good examples: - "Docs: Describe Canvas Doc Block" - "Svelte: Support Svelte v4" Bad examples: - "add new api docs" - "fix: Svelte 4 support" - "Vue: improve docs"
🚫 PR description is missing the mandatory "#### Manual testing" section. Please add it so that reviewers know how to manually test your changes.

Generated by 🚫 dangerJS against f31b2b5

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

Walkthrough

Added new TypeScript tooling and bundling devDependencies. Removed the per-entry dts-process.ts script that spawned parallel declaration generation subprocesses. Replaced the parallel subprocess-based .d.ts generation with a single unified rolldown build in generate-types.ts.

Changes

Cohort / File(s) Summary
Configuration
package.json
Added devDependencies: @typescript/native-preview, oxc-transform, rolldown, and rolldown-plugin-dts for TypeScript tooling and bundling/type generation.
TypeScript Declaration Generation
scripts/build/utils/dts-process.ts, scripts/build/utils/generate-types.ts
Deleted dts-process.ts (removed parallel subprocess spawning with concurrency limits and retry logic). Refactored generate-types.ts to replace per-entry spawning with a single rolldown build for all entries, added external dependency filtering via externalFn matcher, constructed entryMap for entry name–to–path resolution, and simplified logging to iterate over all entries rather than per-subprocess results.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
scripts/build/utils/generate-types.ts (1)

27-33: Consider using normalized path separators for cross-platform compatibility.

The third condition in externalFn uses sep from node:path to check for node_modules dependencies. However, bundlers like Rolldown often normalize resolved paths to forward slashes (/) internally, regardless of platform. On Windows, this could cause the ${sep}node_modules${sep}... pattern to fail if Rolldown passes normalized IDs with forward slashes.

To ensure compatibility across platforms, check for both separators:

🛠️ Suggested fix
 const externalFn = (id: string) =>
   external.some(
     (dep: string) =>
       id === dep ||
       id.startsWith(`${dep}/`) ||
-      id.includes(`${sep}node_modules${sep}${dep}${sep}`)
+      id.includes(`/node_modules/${dep}/`) ||
+      id.includes(`\\node_modules\\${dep}\\`)
   );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/build/utils/generate-types.ts` around lines 27 - 33, The externalFn
check can fail on Windows because it compares id against a pattern containing
node:path sep; update externalFn to normalize the incoming id to use POSIX
separators (or explicitly check both '/' and '\\') before the third condition so
the `${sep}node_modules${sep}${dep}${sep}` match works with Rollup-normalized
IDs; modify the logic in externalFn (referencing the id parameter and the
external array) to use a normalized id variable or a dual-separator check
instead of relying solely on sep.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Around line 67-77: The package.json lists non-existent versions for
oxc-transform, rolldown, and rolldown-plugin-dts which will break installs;
update the dependency entries for "oxc-transform", "rolldown", and
"rolldown-plugin-dts" to published versions (e.g., change "oxc-transform" from
0.121.0 to an available release like 0.99.0, "rolldown" from 1.0.0-rc.12 to an
existing rc such as 1.0.0-rc.9, and "rolldown-plugin-dts" from 0.23.0 to an
available release like 0.9.9) so npm can resolve them.

In `@scripts/build/utils/generate-types.ts`:
- Around line 43-66: The rolldown dts plugin is currently configured with tsgo:
true which is experimental; update the dts plugin config in the rolldown call
(the dts(...) options used when creating out via rolldown) to either use a
stable option (set oxc: true and remove/disable tsgo) or gate tsgo behind a
deliberate opt-in (e.g., only enable tsgo when a specific env flag is set and
leave oxc as the default for CI/production); adjust the dts(...) options (tsgo,
oxc, emitDtsOnly) and add a short comment explaining the chosen behavior.

---

Nitpick comments:
In `@scripts/build/utils/generate-types.ts`:
- Around line 27-33: The externalFn check can fail on Windows because it
compares id against a pattern containing node:path sep; update externalFn to
normalize the incoming id to use POSIX separators (or explicitly check both '/'
and '\\') before the third condition so the
`${sep}node_modules${sep}${dep}${sep}` match works with Rollup-normalized IDs;
modify the logic in externalFn (referencing the id parameter and the external
array) to use a normalized id variable or a dual-separator check instead of
relying solely on sep.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e6bf841a-2a45-44ad-a568-da9bca42a96b

📥 Commits

Reviewing files that changed from the base of the PR and between 1c38a36 and f31b2b5.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • package.json
  • scripts/build/utils/dts-process.ts
  • scripts/build/utils/generate-types.ts
💤 Files with no reviewable changes (1)
  • scripts/build/utils/dts-process.ts

Comment on lines +67 to +77
"@typescript/native-preview": "^7.0.0-dev.20260325.1",
"http-server": "^14.1.1",
"husky": "^9.1.7",
"jiti": "^2.6.1",
"kill-port": "^2.0.1",
"lint-staged": "^16.4.0",
"nx": "^22.6.1",
"oxc-transform": "0.121.0",
"oxfmt": "^0.41.0",
"rolldown": "^1.0.0-rc.12",
"rolldown-plugin-dts": "^0.23.0",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify these packages exist and check their latest versions
echo "=== Checking `@typescript/native-preview` ==="
curl -s "https://registry.npmjs.org/@typescript/native-preview" | jq '.["dist-tags"], .versions | keys[-5:]'

echo "=== Checking oxc-transform ==="
curl -s "https://registry.npmjs.org/oxc-transform" | jq '.["dist-tags"], .versions | keys[-5:]'

echo "=== Checking rolldown ==="
curl -s "https://registry.npmjs.org/rolldown" | jq '.["dist-tags"], .versions | keys[-5:]'

echo "=== Checking rolldown-plugin-dts ==="
curl -s "https://registry.npmjs.org/rolldown-plugin-dts" | jq '.["dist-tags"], .versions | keys[-5:]'

Repository: storybookjs/storybook

Length of output: 624


Package versions 0.121.0, 1.0.0-rc.12, and 0.23.0 do not exist on npm—this will cause installation to fail.

Three of the four new packages specify versions that are not published:

  • oxc-transform 0.121.0: Latest available is 0.99.0 (off by ~22 versions)
  • rolldown 1.0.0-rc.12: Latest available is 1.0.0-rc.9 (off by 3 release candidates)
  • rolldown-plugin-dts 0.23.0: Latest available is 0.9.9 (off by ~2.3x)

Update these to versions that actually exist on npm. @typescript/native-preview ^7.0.0-dev.20260325.1 is fine and will resolve correctly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 67 - 77, The package.json lists non-existent
versions for oxc-transform, rolldown, and rolldown-plugin-dts which will break
installs; update the dependency entries for "oxc-transform", "rolldown", and
"rolldown-plugin-dts" to published versions (e.g., change "oxc-transform" from
0.121.0 to an available release like 0.99.0, "rolldown" from 1.0.0-rc.12 to an
existing rc such as 1.0.0-rc.9, and "rolldown-plugin-dts" from 0.23.0 to an
available release like 0.9.9) so npm can resolve them.

Comment on lines +43 to +66
// Use rolldown + rolldown-plugin-dts with tsgo for fast d.ts generation.
// tsgo (Go-based TypeScript compiler) runs once for all entries (~7s),
// then rolldown bundles the declarations natively in Rust.
const out = await rolldown({
input: entryMap,
external: externalFn,
plugins: [
dts({
cwd,
tsconfig: join(cwd, 'tsconfig.json'),
tsgo: true,
emitDtsOnly: true,
}),
],
logLevel: 'warn',
});

if (dtsProcess.exitCode !== 0) {
if (attempt < MAX_DTS_ATTEMPTS) {
// Race: parallel DTS can read a .d.ts another process is still writing → invalid. Retry + delay usually fixes (flake in core:compile:production since #33759).
console.warn(
`⚠️ DTS failed for ${picocolors.cyan(relative(cwd, entryPoint))}, retrying (${attempt}/${MAX_DTS_ATTEMPTS})...`
);
processes = processes.filter((p) => p !== dtsProcess);
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
continue;
}
console.error(
'\n❌ Generating types for',
picocolors.cyan(relative(cwd, entryPoint)),
' failed'
);
// If any fail after all retries, kill all the other processes and exit (bail)
processes.forEach((p) => p.kill());
processes = [];
process.exit(dtsProcess.exitCode || 1);
}
await out.write({ dir: join(cwd, 'dist'), format: 'es' });

if (!process.env.CI) {
console.log('✅ Generated types for', picocolors.cyan(join(DIR_REL, entryPoint)));
}
break;
}
});
})
);
if (!process.env.CI) {
for (const entry of dtsEntries) {
console.log('Generated types for', picocolors.cyan(join(DIR_REL, entry)));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

What are the configuration options for rolldown-plugin-dts including the tsgo option?

💡 Result:

The rolldown-plugin-dts plugin provides the following configuration options, grouped by category as documented in the official GitHub repository and npm README (latest version 0.22.5 as of March 2026). These enable customization of .d.ts file generation and bundling for Rolldown builds. ### General Options - cwd: Directory to search for tsconfig.json. - dtsInput: boolean, true if entry files are .d.ts (skips generating .d.ts for entry). - emitDtsOnly: boolean, emits only .d.ts files and removes other outputs (useful for CJS .d.ts in separate builds). - tsconfig: Path to tsconfig.json (default: 'tsconfig.json'), or false to ignore. - tsconfigRaw: Raw tsconfig.json object. - compilerOptions: Overrides for compilerOptions from tsconfig.json. - sourcemap: boolean, generates .d.ts.map declaration maps. - resolver: 'oxc' (default, faster) or 'tsc' (more compatible). - cjsDefault: Controls default export emission for CJS. - sideEffects: boolean (default: false), treats .d.ts as having side effects for tree-shaking. ### TSC Options (only when oxc and tsgo are false) - build: boolean, uses tsc --build (true) or plain tsc (false). - vue: boolean, uses vue-tsc for .d.ts generation. - parallel: boolean, launches separate process for parallel tsc/vue-tsc. - emitJs: boolean, emits .d.ts for .js files (auto-enabled if allowJs true). ### Oxc Options - oxc: boolean, uses Oxc for faster .d.ts generation (auto-enabled if isolatedDeclarations true). ### TypeScript Go (tsgo) Option - Experimental - tsgo: boolean | TsgoOptions. Enables experimental DTS generation using tsgo (requires @typescript/native-preview). Ignores tsconfigRaw and compilerOptions. Not recommended for production. - As boolean (true): Uses tsgo from @typescript/native-preview. - As object: e.g., { path: '/path/to/tsgo' } for custom tsgo binary. Example usage: import { dts } from 'rolldown-plugin-dts'; export default { plugins: [dts({ tsgo: true, sourcemap: true })] }; Note: For code splitting, configure groups so .d.ts chunks end with .d (e.g., test: /foo.*.d.[cm]?ts$/).

Citations:


Flag: tsgo is experimental and not recommended for production.

The rolldown configuration uses tsgo: true and emitDtsOnly: true for type generation. While emitDtsOnly correctly ensures only .d.ts files are emitted, the tsgo option has a significant caveat: according to the rolldown-plugin-dts documentation, tsgo is experimental and explicitly not recommended for production use. It requires @typescript/native-preview and may have unexpected behavior in production builds.

Consider either:

  1. Using oxc: true (the stable default) instead of tsgo, or
  2. Explicitly documenting that this experimental feature is intentional for local development performance, with clear understanding of the trade-offs.

Error handling is correct—failures will propagate to the caller as expected.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/build/utils/generate-types.ts` around lines 43 - 66, The rolldown dts
plugin is currently configured with tsgo: true which is experimental; update the
dts plugin config in the rolldown call (the dts(...) options used when creating
out via rolldown) to either use a stable option (set oxc: true and
remove/disable tsgo) or gate tsgo behind a deliberate opt-in (e.g., only enable
tsgo when a specific env flag is set and leave oxc as the default for
CI/production); adjust the dts(...) options (tsgo, oxc, emitDtsOnly) and add a
short comment explaining the chosen behavior.

@nx-cloud
Copy link

nx-cloud bot commented Mar 26, 2026

View your CI Pipeline Execution ↗ for commit f31b2b5

Command Status Duration Result
nx run-many -t compile,check,knip,test,lint,fmt... ⛔ Cancelled 14m 4s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-26 04:05:37 UTC

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants