From 25718db38604481fd98d4b069738a282b1b4a1da Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Tue, 14 Jul 2026 05:02:31 +0000 Subject: [PATCH 1/4] refactor(ui): consolidate getPluginColor branding palette into devtools-ui Move the canonical predefinedColorMap/getPluginColor (branding hues, hex-vs-hue branch) from packages/rolldown/src/app/utils/color.ts into packages/ui/src/utils/color.ts, merging its test cases. Both rolldown and vite apps now import getPluginColor from @vitejs/devtools-ui/utils/color instead of maintaining their own copies. vite's palette previously dropped the bailout/vite1/vite2/rolldown/nuxt branding hues; it now matches rolldown's. --- .../display/HighlightedPackageName.ts | 2 +- .../app/components/display/HighlightedPath.ts | 2 +- .../src/app/utils/__tests__/color.test.ts | 20 -------- packages/rolldown/src/app/utils/color.ts | 46 ------------------- packages/ui/src/utils/__tests__/color.test.ts | 19 +++++++- packages/ui/src/utils/color.ts | 36 +++++++++++++-- .../app/components/display/HighlightedPath.ts | 2 +- packages/vite/src/app/utils/color.ts | 16 ------- 8 files changed, 54 insertions(+), 89 deletions(-) delete mode 100644 packages/rolldown/src/app/utils/__tests__/color.test.ts delete mode 100644 packages/rolldown/src/app/utils/color.ts delete mode 100644 packages/vite/src/app/utils/color.ts diff --git a/packages/rolldown/src/app/components/display/HighlightedPackageName.ts b/packages/rolldown/src/app/components/display/HighlightedPackageName.ts index 6fd18e10..0ec1d0be 100644 --- a/packages/rolldown/src/app/components/display/HighlightedPackageName.ts +++ b/packages/rolldown/src/app/components/display/HighlightedPackageName.ts @@ -1,6 +1,6 @@ +import { getPluginColor } from '@vitejs/devtools-ui/utils/color' import { defineComponent, h } from 'vue' import { isPackageName } from '~~/shared/utils/filepath' -import { getPluginColor } from '~/utils/color' // @unocss-include export default defineComponent({ diff --git a/packages/rolldown/src/app/components/display/HighlightedPath.ts b/packages/rolldown/src/app/components/display/HighlightedPath.ts index 07e790ca..bdd09b7c 100644 --- a/packages/rolldown/src/app/components/display/HighlightedPath.ts +++ b/packages/rolldown/src/app/components/display/HighlightedPath.ts @@ -1,5 +1,5 @@ +import { getPluginColor } from '@vitejs/devtools-ui/utils/color' import { defineComponent, h } from 'vue' -import { getPluginColor } from '~/utils/color' // @unocss-include export default defineComponent({ diff --git a/packages/rolldown/src/app/utils/__tests__/color.test.ts b/packages/rolldown/src/app/utils/__tests__/color.test.ts deleted file mode 100644 index 710d9c50..00000000 --- a/packages/rolldown/src/app/utils/__tests__/color.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { getHashColorFromString, getHsla } from '@vitejs/devtools-ui/utils/color' -import { describe, expect, it } from 'vitest' -import { getPluginColor, predefinedColorMap } from '../color' - -describe('getPluginColor', () => { - it('should use predefinedColorMap with known name', () => { - for (const name in predefinedColorMap) { - if (Object.hasOwn(predefinedColorMap, name) - && name === name.replace(/[^a-z]+/gi, '').toLowerCase()) { - if (typeof predefinedColorMap[name] === 'number') { - expect(getPluginColor(`8080-=(🤔)${name}`)).toBe(getHsla(predefinedColorMap[name])) - } - } - } - }) - - it('should use getHashColorFromString with unknown name', () => { - expect(getPluginColor('😄Foo')).toBe(getHashColorFromString('foo')) - }) -}) diff --git a/packages/rolldown/src/app/utils/color.ts b/packages/rolldown/src/app/utils/color.ts deleted file mode 100644 index 5cbcb874..00000000 --- a/packages/rolldown/src/app/utils/color.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { getHashColorFromString, getHsla } from '@vitejs/devtools-ui/utils/color' - -/** - * Predefined color map for matching the branding - * - * Accept a 6-digit hex color string or a hue number - * Hue numbers are preferred because they will adapt better contrast in light/dark mode - * - * Hue numbers reference: - * - 0: red - * - 30: orange - * - 60: yellow - * - 120: green - * - 180: cyan - * - 240: blue - * - 270: purple - */ -export const predefinedColorMap = { - error: 0, - client: 60, - bailout: -1, - ssr: 270, - vite: 250, - vite1: 240, - vite2: 120, - rolldown: 18, - virtual: 160, - nuxt: 140, -} as Record - -export function getPluginColor(name: string, opacity = 1): string { - name = name.replace(/[^a-z]+/gi, '').toLowerCase() - if (name in predefinedColorMap) { - const color = predefinedColorMap[name]! - if (typeof color === 'number') { - return getHsla(color, opacity) - } - else { - if (opacity === 1) - return color - const opacityHex = Math.floor(opacity * 255).toString(16).padStart(2, '0') - return color + opacityHex - } - } - return getHashColorFromString(name, opacity) -} diff --git a/packages/ui/src/utils/__tests__/color.test.ts b/packages/ui/src/utils/__tests__/color.test.ts index b8baa0dc..d98d8773 100644 --- a/packages/ui/src/utils/__tests__/color.test.ts +++ b/packages/ui/src/utils/__tests__/color.test.ts @@ -1,6 +1,6 @@ import { isDark } from '@vitejs/devtools-ui/composables/dark' import { beforeEach, describe, expect, it } from 'vitest' -import { getHashColorFromString, getHsla } from '../color' +import { getHashColorFromString, getHsla, getPluginColor, predefinedColorMap } from '../color' describe('getHashColorFromString', () => { it('should get the same color with the same string', () => { @@ -34,3 +34,20 @@ describe('getHsla', () => { expect(getHsla(180, 0.8)).toBe('hsla(180, 50%, 60%, 0.8)') }) }) + +describe('getPluginColor', () => { + it('should use predefinedColorMap with known name', () => { + for (const name in predefinedColorMap) { + if (Object.hasOwn(predefinedColorMap, name) + && name === name.replace(/[^a-z]+/gi, '').toLowerCase()) { + if (typeof predefinedColorMap[name] === 'number') { + expect(getPluginColor(`8080-=(🤔)${name}`)).toBe(getHsla(predefinedColorMap[name])) + } + } + } + }) + + it('should use getHashColorFromString with unknown name', () => { + expect(getPluginColor('😄Foo')).toBe(getHashColorFromString('foo')) + }) +}) diff --git a/packages/ui/src/utils/color.ts b/packages/ui/src/utils/color.ts index 306ff735..48249efa 100644 --- a/packages/ui/src/utils/color.ts +++ b/packages/ui/src/utils/color.ts @@ -20,17 +20,47 @@ export function getHsla( return `hsla(${hue}, ${saturation}%, ${lightness}%, ${opacity})` } -export const predefinedPluginColorMap = { +/** + * Predefined color map for matching the branding + * + * Accept a 6-digit hex color string or a hue number + * Hue numbers are preferred because they will adapt better contrast in light/dark mode + * + * Hue numbers reference: + * - 0: red + * - 30: orange + * - 60: yellow + * - 120: green + * - 180: cyan + * - 240: blue + * - 270: purple + */ +export const predefinedColorMap = { error: 0, client: 60, + bailout: -1, ssr: 270, vite: 250, + vite1: 240, + vite2: 120, + rolldown: 18, virtual: 160, + nuxt: 140, } as Record export function getPluginColor(name: string, opacity = 1): string { name = name.replace(/[^a-z]+/gi, '').toLowerCase() - if (name in predefinedPluginColorMap) - return getHsla(predefinedPluginColorMap[name]!, opacity) + if (name in predefinedColorMap) { + const color = predefinedColorMap[name]! + if (typeof color === 'number') { + return getHsla(color, opacity) + } + else { + if (opacity === 1) + return color + const opacityHex = Math.floor(opacity * 255).toString(16).padStart(2, '0') + return color + opacityHex + } + } return getHashColorFromString(name, opacity) } diff --git a/packages/vite/src/app/components/display/HighlightedPath.ts b/packages/vite/src/app/components/display/HighlightedPath.ts index 21405e20..ef4c7dba 100644 --- a/packages/vite/src/app/components/display/HighlightedPath.ts +++ b/packages/vite/src/app/components/display/HighlightedPath.ts @@ -1,5 +1,5 @@ +import { getPluginColor } from '@vitejs/devtools-ui/utils/color' import { defineComponent, h } from 'vue' -import { getPluginColor } from '~/utils/color' // @unocss-include export default defineComponent({ diff --git a/packages/vite/src/app/utils/color.ts b/packages/vite/src/app/utils/color.ts deleted file mode 100644 index b2bc84c4..00000000 --- a/packages/vite/src/app/utils/color.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { getHashColorFromString, getHsla } from '@vitejs/devtools-ui/utils/color' - -export const predefinedColorMap = { - error: 0, - client: 60, - ssr: 270, - vite: 250, - virtual: 160, -} as Record - -export function getPluginColor(name: string, opacity = 1): string { - name = name.replace(/[^a-z]+/gi, '').toLowerCase() - if (name in predefinedColorMap) - return getHsla(predefinedColorMap[name]!, opacity) - return getHashColorFromString(name, opacity) -} From 43165c046ea10376f1319d44e083e52c351ae335 Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Tue, 14 Jul 2026 05:02:50 +0000 Subject: [PATCH 2/4] refactor(ui): consolidate format utils (bytesToHumanSize/toTree/normalizeTimestamp) into devtools-ui Move bytesToHumanSize, getContentByteSize, toTree and normalizeTimestamp from the duplicated packages/{rolldown,vite}/src/app/utils/format.ts into packages/ui/src/utils/format.ts alongside the existing formatDuration, generalizing toTree/ModuleTreeNode over a generic module-shape so both apps' own module types keep working unchanged. Both apps now import these from @vitejs/devtools-ui/utils/format. Folds in vite's bytes||1 guard against -Infinity on a 0-byte input, and rolldown's defensive null checks in toTree, for both apps. --- .../src/app/components/assets/Folder.vue | 2 +- .../app/components/chart/ModuleFlamegraph.vue | 2 +- .../src/app/components/compare/DeltaValue.vue | 2 +- .../src/app/components/compare/MetricCard.vue | 2 +- .../src/app/components/compare/TabView.vue | 2 +- .../components/data/PluginDetailsLoader.vue | 3 +- .../components/data/PluginDetailsTable.vue | 2 +- .../app/components/display/FileSizeBadge.vue | 2 +- .../src/app/components/modules/Folder.vue | 2 +- .../rolldown/src/app/composables/chart.ts | 2 +- packages/rolldown/src/app/utils/format.ts | 72 ---------------- .../src}/utils/__tests__/format.test.ts | 35 +++++++- packages/ui/src/utils/format.ts | 82 +++++++++++++++++++ .../app/components/chart/ModuleFlamegraph.vue | 2 +- .../components/data/PluginDetailsLoader.vue | 3 +- .../components/data/PluginDetailsTable.vue | 2 +- .../app/components/display/FileSizeBadge.vue | 2 +- .../src/app/components/modules/Folder.vue | 2 +- packages/vite/src/app/composables/chart.ts | 2 +- packages/vite/src/app/utils/format.ts | 61 -------------- 20 files changed, 131 insertions(+), 153 deletions(-) delete mode 100644 packages/rolldown/src/app/utils/format.ts rename packages/{rolldown/src/app => ui/src}/utils/__tests__/format.test.ts (70%) delete mode 100644 packages/vite/src/app/utils/format.ts diff --git a/packages/rolldown/src/app/components/assets/Folder.vue b/packages/rolldown/src/app/components/assets/Folder.vue index 6cab1344..af319f1d 100644 --- a/packages/rolldown/src/app/components/assets/Folder.vue +++ b/packages/rolldown/src/app/components/assets/Folder.vue @@ -1,7 +1,7 @@