From 269fc0c7a1b89d7c780460f5a6de4e95d821f079 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 9 Feb 2026 23:18:32 +0100 Subject: [PATCH] Fix CSS entry points plugin to avoid duplicate emissions - Add deduplication logic to only emit CSS once per output directory - Only emit during write phase, not during generate - Fix comment describing the path transformation Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .../src/modules/build/lib/builder/plugins.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/modules/build/lib/builder/plugins.ts b/packages/cli/src/modules/build/lib/builder/plugins.ts index 68d56780ad..2340884e3d 100644 --- a/packages/cli/src/modules/build/lib/builder/plugins.ts +++ b/packages/cli/src/modules/build/lib/builder/plugins.ts @@ -186,13 +186,27 @@ interface CssEntryPointsOptions { export function cssEntryPoints(options: CssEntryPointsOptions): Plugin { const cssEntries = options.entryPoints.filter(ep => ep.ext === '.css'); + // Track output directories we've already emitted CSS to, to avoid duplicates + // when Rollup runs generateBundle multiple times (once per output format) + const generatedFor = new Set(); + return { name: 'backstage-css-entry-points', - async generateBundle() { + async generateBundle(outputOptions, _bundle, isWrite) { + if (!isWrite) { + return; + } + + const dir = outputOptions.dir || dirname(outputOptions.file!); + if (generatedFor.has(dir)) { + return; + } + generatedFor.add(dir); + for (const entryPoint of cssEntries) { const sourcePath = resolvePath(options.targetDir, entryPoint.path); - // Convert src/ path to dist/ path for output filename + // Strip the src/ prefix to create an output filename relative to the Rollup output directory const outputPath = entryPoint.path.replace(/^(\.\/)?src\//, ''); // Read source CSS