Skip to content
Closed
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
2 changes: 1 addition & 1 deletion nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,5 +205,5 @@
]
},
"analytics": false,
"codexCacheBust": "2026-03-23T12:57:22Z"
"codexCacheBust": "2026-03-26T08:49:19Z"
}
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,17 @@
"@nx/workspace": "^22.6.1",
"@playwright/test": "^1.58.2",
"@types/kill-port": "^2.0.3",
"@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",
Comment on lines +67 to +77

Copy link
Copy Markdown
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.

"std-env": "^4.0.0",
"vite": "^7.0.4",
"vitest": "^4.1.0"
Expand Down
70 changes: 0 additions & 70 deletions scripts/build/utils/dts-process.ts

This file was deleted.

134 changes: 46 additions & 88 deletions scripts/build/utils/generate-types.ts
Original file line number Diff line number Diff line change
@@ -1,109 +1,67 @@
import { spawn } from 'child_process';
import limit from 'p-limit';
import { sep } from 'node:path';

import { join, relative } from 'pathe';
import picocolors from 'picocolors';
import { rolldown } from 'rolldown';
import { dts } from 'rolldown-plugin-dts';

import { ROOT_DIRECTORY } from '../../utils/constants';
import type { BuildEntries } from './entry-utils';
import { getExternal } from './entry-utils';

const DIR_CODE = join(import.meta.dirname, '..', '..', '..', 'code');

const MAX_DTS_ATTEMPTS = 2;
const RETRY_DELAY_MS = 500;

export async function generateTypesFiles(cwd: string, data: BuildEntries) {
const DIR_CWD = cwd;
const DIR_REL = relative(DIR_CODE, DIR_CWD);
const DIR_REL = relative(DIR_CODE, cwd);

const dtsEntries = Object.values(data.entries)
.flat()
.filter((entry) => entry.dts !== false)
.map((e) => e.entryPoint);

// Spawn each entry in it's own separate process, because they are slow & synchronous
// ...this way we do not bog down the main process/esbuild and can run them in parallel
// we limit the number of concurrent processes to 3, because we don't want to overload the host machine
// by trial and error, 3 seems to be the sweet spot between perf and consistency
const limited = limit(5);
let processes: ReturnType<typeof spawn>[] = [];

await Promise.all(
dtsEntries.map(async (entryPoint) => {
return limited(async () => {
for (let attempt = 1; attempt <= MAX_DTS_ATTEMPTS; attempt++) {
let timer: ReturnType<typeof setTimeout> | undefined;
const dtsProcess = spawn(
`"${join(ROOT_DIRECTORY, 'node_modules', '.bin', 'jiti')}"`,
[`"${join(import.meta.dirname, 'dts-process.ts')}"`, `"${entryPoint}"`],
{
shell: true,
cwd: DIR_CWD,
stdio: ['ignore', 'inherit', 'pipe'],
}
);
processes.push(dtsProcess);
if (dtsEntries.length === 0) {
return;
}

// Filter stderr to exclude messages containing "are imported from external module", which is an ignorable warning from rollup
dtsProcess.stderr?.on('data', (data) => {
const message = data.toString();
if (!message.includes('are imported from external module')) {
process.stderr.write(data);
}
});
const { typesExternal: external } = await getExternal(cwd);

await Promise.race([
new Promise((resolve) => {
dtsProcess.on('exit', () => {
resolve(void 0);
});
dtsProcess.on('error', () => {
resolve(void 0);
});
dtsProcess.on('close', () => {
resolve(void 0);
});
}),
new Promise((resolve) => {
timer = setTimeout(() => {
console.log('⌛ Timed out generating d.ts files for', entryPoint);
const externalFn = (id: string) =>
external.some(
(dep: string) =>
id === dep ||
id.startsWith(`${dep}/`) ||
id.includes(`${sep}node_modules${sep}${dep}${sep}`)
);

dtsProcess.kill(408); // timed out
resolve(void 0);
}, 120000);
}),
]);
// Build entry map: { 'client-logger/index': '/absolute/path/src/client-logger/index.ts', ... }
const entryMap: Record<string, string> = {};
for (const entry of dtsEntries) {
// ./src/client-logger/index.ts -> client-logger/index
const name = entry.replace(/^\.\/src\//, '').replace(/\.tsx?$/, '');
entryMap[name] = join(cwd, entry);
}

if (timer) {
clearTimeout(timer);
}
// 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)));
}
}
Comment on lines +43 to +66

Copy link
Copy Markdown
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.

}
Loading
Loading