From 65a3215a104886ce6e0f4b8098418d7e2e1ad94c Mon Sep 17 00:00:00 2001 From: Raashish Aggarwal <94279692+raashish1601@users.noreply.github.com> Date: Sat, 28 Mar 2026 02:02:02 +0530 Subject: [PATCH 1/3] fix: dedupe builder-vite project annotation imports --- .../src/codegen-project-annotations.test.ts | 24 +++++++++++++++++++ .../src/codegen-project-annotations.ts | 12 +++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 code/builders/builder-vite/src/codegen-project-annotations.test.ts diff --git a/code/builders/builder-vite/src/codegen-project-annotations.test.ts b/code/builders/builder-vite/src/codegen-project-annotations.test.ts new file mode 100644 index 000000000000..cac7eb314088 --- /dev/null +++ b/code/builders/builder-vite/src/codegen-project-annotations.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest'; + +import { generateProjectAnnotationsCodeFromPreviews } from './codegen-project-annotations'; + +describe('generateProjectAnnotationsCodeFromPreviews', () => { + it('keeps generated preview import identifiers unique when aliases collide', () => { + const result = generateProjectAnnotationsCodeFromPreviews({ + // These paths previously produced the same generated `preview_` identifier. + previewAnnotations: ['/virtual/path/0000r/preview.js', '/virtual/path/00020/preview.js'], + projectRoot: '/virtual', + frameworkName: 'frameworkName', + isCsf4: false, + }); + + const importVariables = [...result.matchAll(/import \* as (\w+) from/g)].map( + (match) => match[1] + ); + + expect(importVariables).toHaveLength(2); + expect(new Set(importVariables).size).toBe(importVariables.length); + expect(result).toContain(`hmrPreviewAnnotationModules[0] ?? ${importVariables[0]}`); + expect(result).toContain(`hmrPreviewAnnotationModules[1] ?? ${importVariables[1]}`); + }); +}); diff --git a/code/builders/builder-vite/src/codegen-project-annotations.ts b/code/builders/builder-vite/src/codegen-project-annotations.ts index 1f5b5192145d..8cd5f37098a7 100644 --- a/code/builders/builder-vite/src/codegen-project-annotations.ts +++ b/code/builders/builder-vite/src/codegen-project-annotations.ts @@ -44,11 +44,21 @@ export function generateProjectAnnotationsCodeFromPreviews(options: { const variables: string[] = []; const imports: string[] = []; + const usedVariables = new Set(); for (const previewAnnotation of previewAnnotationURLs) { - const variable = + const baseVariable = genSafeVariableName(filename(previewAnnotation)).replace(/_(45|46|47)/g, '_') + '_' + hash(previewAnnotation); + let variable = baseVariable; + let duplicateCount = 2; + + while (usedVariables.has(variable)) { + variable = `${baseVariable}_${duplicateCount}`; + duplicateCount += 1; + } + + usedVariables.add(variable); variables.push(variable); imports.push(genImport(previewAnnotation, { name: '*', as: variable })); } From 784986806a07aadf9f859d6066595f1c2732b34d Mon Sep 17 00:00:00 2001 From: Raashish Aggarwal <94279692+raashish1601@users.noreply.github.com> Date: Sat, 28 Mar 2026 03:10:02 +0530 Subject: [PATCH 2/3] test: lock repeated builder-vite alias collisions --- .../src/codegen-project-annotations.test.ts | 25 +++++++++++++++++++ .../src/codegen-project-annotations.ts | 25 +++++++++++-------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/code/builders/builder-vite/src/codegen-project-annotations.test.ts b/code/builders/builder-vite/src/codegen-project-annotations.test.ts index cac7eb314088..eb5cc464cd64 100644 --- a/code/builders/builder-vite/src/codegen-project-annotations.test.ts +++ b/code/builders/builder-vite/src/codegen-project-annotations.test.ts @@ -21,4 +21,29 @@ describe('generateProjectAnnotationsCodeFromPreviews', () => { expect(result).toContain(`hmrPreviewAnnotationModules[0] ?? ${importVariables[0]}`); expect(result).toContain(`hmrPreviewAnnotationModules[1] ?? ${importVariables[1]}`); }); + + it('suffixes repeated collisions deterministically across more than two previews', () => { + const result = generateProjectAnnotationsCodeFromPreviews({ + // These paths all collide under the current djb2 hash, so the fallback suffixing stays active. + previewAnnotations: [ + '/virtual/path/0000r/preview.js', + '/virtual/path/00020/preview.js', + '/virtual/path/0001Q/preview.js', + ], + projectRoot: '/virtual', + frameworkName: 'frameworkName', + isCsf4: false, + }); + + const importVariables = [...result.matchAll(/import \* as (\w+) from/g)].map( + (match) => match[1] + ); + + expect(importVariables).toEqual([ + importVariables[0], + `${importVariables[0]}_2`, + `${importVariables[0]}_3`, + ]); + expect(result).toContain(`hmrPreviewAnnotationModules[2] ?? ${importVariables[2]}`); + }); }); diff --git a/code/builders/builder-vite/src/codegen-project-annotations.ts b/code/builders/builder-vite/src/codegen-project-annotations.ts index 8cd5f37098a7..7d2e9a585c9e 100644 --- a/code/builders/builder-vite/src/codegen-project-annotations.ts +++ b/code/builders/builder-vite/src/codegen-project-annotations.ts @@ -50,15 +50,7 @@ export function generateProjectAnnotationsCodeFromPreviews(options: { genSafeVariableName(filename(previewAnnotation)).replace(/_(45|46|47)/g, '_') + '_' + hash(previewAnnotation); - let variable = baseVariable; - let duplicateCount = 2; - - while (usedVariables.has(variable)) { - variable = `${baseVariable}_${duplicateCount}`; - duplicateCount += 1; - } - - usedVariables.add(variable); + const variable = getUniqueImportVariable(baseVariable, usedVariables); variables.push(variable); imports.push(genImport(previewAnnotation, { name: '*', as: variable })); } @@ -115,7 +107,20 @@ export function generateProjectAnnotationsCodeFromPreviews(options: { `.trim(); } -/** djb2 hash — http://www.cse.yorku.ca/~oz/hash.html */ +function getUniqueImportVariable(baseVariable: string, usedVariables: Set) { + let variable = baseVariable; + let duplicateCount = 2; + + while (usedVariables.has(variable)) { + variable = `${baseVariable}_${duplicateCount}`; + duplicateCount += 1; + } + + usedVariables.add(variable); + return variable; +} + +/** djb2 hash - http://www.cse.yorku.ca/~oz/hash.html */ function hash(value: string) { let acc = 5381; for (let i = 0; i < value.length; i++) { From 6d0acc7b044d69de565114d0e4d3f68121d86ff1 Mon Sep 17 00:00:00 2001 From: Raashish Aggarwal <94279692+raashish1601@users.noreply.github.com> Date: Sat, 28 Mar 2026 03:55:34 +0530 Subject: [PATCH 3/3] test: assert base builder-vite alias identifier --- .../builder-vite/src/codegen-project-annotations.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/code/builders/builder-vite/src/codegen-project-annotations.test.ts b/code/builders/builder-vite/src/codegen-project-annotations.test.ts index eb5cc464cd64..46b9d5d8a39e 100644 --- a/code/builders/builder-vite/src/codegen-project-annotations.test.ts +++ b/code/builders/builder-vite/src/codegen-project-annotations.test.ts @@ -39,6 +39,7 @@ describe('generateProjectAnnotationsCodeFromPreviews', () => { (match) => match[1] ); + expect(importVariables[0]).toMatch(/^[A-Za-z_$][A-Za-z0-9_$]*$/); expect(importVariables).toEqual([ importVariables[0], `${importVariables[0]}_2`,