From f6a5d2f07f92e31efdcb33f0cfa7820e6ebbcf24 Mon Sep 17 00:00:00 2001 From: Johan Persson Date: Tue, 20 Jan 2026 11:06:23 +0100 Subject: [PATCH] fix(cli): use content-based hashing for CSS module class names Replace the default path-based CSS module hash with a content-based hash derived from the CSS content. This prevents class name collisions when multiple versions of packages are loaded simultaneously. Uses 10 characters of hex-encoded MD5 hash for safe, readable class name suffixes. Signed-off-by: Johan Persson --- .changeset/orange-hoops-matter.md | 5 +++++ .../cli/src/modules/build/lib/builder/config.ts | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 .changeset/orange-hoops-matter.md diff --git a/.changeset/orange-hoops-matter.md b/.changeset/orange-hoops-matter.md new file mode 100644 index 0000000000..7632915f23 --- /dev/null +++ b/.changeset/orange-hoops-matter.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fixed CSS module class name collisions when running multiple versions of packages simultaneously by using content-based hashing for class name generation. diff --git a/packages/cli/src/modules/build/lib/builder/config.ts b/packages/cli/src/modules/build/lib/builder/config.ts index 3e360b645c..7776571e43 100644 --- a/packages/cli/src/modules/build/lib/builder/config.ts +++ b/packages/cli/src/modules/build/lib/builder/config.ts @@ -16,7 +16,9 @@ import chalk from 'chalk'; import fs from 'fs-extra'; +import { createHash } from 'crypto'; import { + basename, extname, relative as relativePath, resolve as resolvePath, @@ -239,7 +241,18 @@ export async function makeRollupConfigs( include: /node_modules/, exclude: [/\/[^/]+\.(?:stories|test)\.[^/]+$/], }), - postcss(), + postcss({ + modules: { + generateScopedName(name: string, filename: string, css: string) { + const hash = createHash('md5') + .update(css) + .digest('hex') + .slice(0, 10); + const file = basename(filename, '.module.css'); + return `${file}_${name}__${hash}`; + }, + }, + }), forwardFileImports({ exclude: /\.icon\.svg$/, include: [