From 3d86a6fe7aea6bec4fc08a8526a9c12b5279d694 Mon Sep 17 00:00:00 2001 From: Sakana <15715093608@163.com> Date: Thu, 5 Nov 2026 16:20:54 +0800 Subject: [PATCH] fix(rolldown): preserve missing and zero comparison metrics --- .../src/app/components/compare/DeltaValue.vue | 9 ++- .../app/components/compare/SingleSideRow.vue | 2 +- .../src/app/components/compare/SplitRow.vue | 10 +-- .../src/app/components/compare/TabView.vue | 61 +++++++++++-------- .../app/components/modules/BuildMetrics.vue | 6 +- .../__tests__/reader-index-cache.test.ts | 14 +++-- .../rolldown/src/node/rolldown/log-cache.ts | 11 ++-- .../node/rpc/__tests__/module-compare.test.ts | 50 +++++++++++++++ .../rolldown-get-session-compare-details.ts | 13 ++-- packages/rolldown/src/shared/types/data.ts | 12 ++-- .../utils/__tests__/compare-metrics.test.ts | 22 +++++++ .../src/shared/utils/compare-metrics.ts | 25 ++++++++ 12 files changed, 177 insertions(+), 58 deletions(-) create mode 100644 packages/rolldown/src/node/rpc/__tests__/module-compare.test.ts create mode 100644 packages/rolldown/src/shared/utils/__tests__/compare-metrics.test.ts create mode 100644 packages/rolldown/src/shared/utils/compare-metrics.ts diff --git a/packages/rolldown/src/app/components/compare/DeltaValue.vue b/packages/rolldown/src/app/components/compare/DeltaValue.vue index aa5a0770..1389fac8 100644 --- a/packages/rolldown/src/app/components/compare/DeltaValue.vue +++ b/packages/rolldown/src/app/components/compare/DeltaValue.vue @@ -3,7 +3,7 @@ import { bytesToHumanSize } from '@vitejs/devtools-ui/utils/format' import { computed } from 'vue' const props = withDefaults(defineProps<{ - value: number + value: number | null format?: 'bytes' | 'duration' | 'number' signed?: boolean }>(), { @@ -12,18 +12,21 @@ const props = withDefaults(defineProps<{ }) const sign = computed(() => { - if (!props.signed || props.value === 0) + if (!props.signed || props.value == null || props.value === 0) return '' return props.value > 0 ? '+' : '-' }) const colorClass = computed(() => { - if (!props.signed || props.value === 0) + if (!props.signed || props.value == null || props.value === 0) return 'text-gray-500' return props.value > 0 ? 'text-red-500' : 'text-green-500' }) const formatted = computed(() => { + if (props.value == null) + return { amount: 'Unavailable', unit: '' } + const value = props.signed ? Math.abs(props.value) : props.value if (props.format === 'bytes') { diff --git a/packages/rolldown/src/app/components/compare/SingleSideRow.vue b/packages/rolldown/src/app/components/compare/SingleSideRow.vue index 1d075457..9809dc0c 100644 --- a/packages/rolldown/src/app/components/compare/SingleSideRow.vue +++ b/packages/rolldown/src/app/components/compare/SingleSideRow.vue @@ -11,7 +11,7 @@ withDefaults(defineProps<{ sessionLabel: string title: string titleMeta?: string - delta: number + delta: number | null format: 'bytes' | 'duration' | 'number' subtitle?: string link?: string diff --git a/packages/rolldown/src/app/components/compare/SplitRow.vue b/packages/rolldown/src/app/components/compare/SplitRow.vue index 29156864..e2a5ced3 100644 --- a/packages/rolldown/src/app/components/compare/SplitRow.vue +++ b/packages/rolldown/src/app/components/compare/SplitRow.vue @@ -22,9 +22,9 @@ const props = withDefaults(defineProps<{ currentStats?: SplitDiffStat[] previousBadges?: string[] currentBadges?: string[] - previous: number - current: number - delta: number + previous: number | null + current: number | null + delta: number | null format: 'bytes' | 'duration' | 'number' ratioText?: string selectable?: boolean @@ -42,9 +42,9 @@ const emit = defineEmits<{ }>() const ratioClass = computed(() => { - if (props.delta > 0) + if (props.delta != null && props.delta > 0) return 'text-red-500' - if (props.delta < 0) + if (props.delta != null && props.delta < 0) return 'text-green-500' return 'text-gray-500' }) diff --git a/packages/rolldown/src/app/components/compare/TabView.vue b/packages/rolldown/src/app/components/compare/TabView.vue index 241d2e29..5da85b6b 100644 --- a/packages/rolldown/src/app/components/compare/TabView.vue +++ b/packages/rolldown/src/app/components/compare/TabView.vue @@ -7,10 +7,11 @@ import type { } from '~~/shared/types' import { bytesToHumanSize } from '@vitejs/devtools-ui/utils/format' import { computed, ref, watch } from 'vue' +import { formatMetricRatio, sumMetrics } from '~~/shared/utils/compare-metrics' import { useRoute, useRouter } from '#app/composables/router' type CompareTab = 'overview' | 'plugins' | 'chunks' | 'modules' | 'assets' | 'packages' -type DiffMode = 'changed' | 'added' | 'removed' +type DiffMode = 'changed' | 'added' | 'removed' | 'unavailable' type DiffFormat = 'bytes' | 'duration' | 'number' type SummaryTone = 'increase' | 'decrease' @@ -29,7 +30,7 @@ interface SplitDiffStat { hidden?: boolean } -interface SplitDiffRow extends SessionCompareMetricValue { +interface SplitDiffRow extends SessionCompareMetricValue { key: string status: SessionCompareChangeStatus previousTitle?: string @@ -253,7 +254,7 @@ const sessionSummaries = computed(() => { }, { label: 'Calls', - value: pluginStats.calls.toLocaleString(), + value: pluginStats.calls?.toLocaleString() ?? 'Unavailable', icon: 'i-ph-arrow-counter-clockwise-duotone', tone: getSummaryTone(index, pluginStats.calls, pluginStatsA.calls), }, @@ -416,12 +417,16 @@ const activeRows = computed(() => { } }) +const unavailableRows = computed(() => activeRows.value.filter(item => item.status === 'unavailable')) + const changedRows = computed(() => activeRows.value.filter(item => item.status === 'changed')) const addedRows = computed(() => activeRows.value.filter(item => item.status === 'added')) const removedRows = computed(() => activeRows.value.filter(item => item.status === 'removed')) const activeDiffRows = computed(() => { switch (activeDiffMode.value) { + case 'unavailable': + return unavailableRows.value case 'added': return addedRows.value case 'removed': @@ -438,7 +443,7 @@ const diffModeOptions = computed>(() => { return [ @@ -469,6 +474,17 @@ const diffModeOptions = computed activeRows.value[0]?.format || 'bytes') const activeDiffEmptyText = computed(() => { switch (activeDiffMode.value) { + case 'unavailable': + return 'No unavailable measurements' case 'added': return 'No added entries' case 'removed': @@ -607,20 +625,13 @@ function getStatTone(value: number, baseline: number | undefined): SplitDiffStat function createSplitRow(row: Omit): SplitDiffRow { return { ...row, - ratioText: formatRatio(row), + ratioText: formatMetricRatio(row), } } -function formatRatio(item: SessionCompareMetricValue) { - if (item.deltaRatio == null) - return item.previous === 0 && item.current > 0 ? 'new' : '-' - if (item.deltaRatio === 0) - return '0%' - const sign = item.deltaRatio > 0 ? '+' : '' - return `${sign}${(item.deltaRatio * 100).toFixed(2)}%` -} - -function formatValue(value: number, format: DiffFormat) { +function formatValue(value: number | null, format: DiffFormat) { + if (value == null) + return 'Unavailable' if (format === 'duration') { if (value >= 1000) return `${+(value / 1000).toFixed(2)}s` @@ -630,14 +641,16 @@ function formatValue(value: number, format: DiffFormat) { return value.toLocaleString() } -function formatBytesSummary(value: number) { +function formatBytesSummary(value: number | null) { + if (value == null) + return 'Unavailable' if (!value) return '0 B' return bytesToHumanSize(value).join(' ') } -function getSummaryTone(index: number, value: number, baseline: number | undefined): SummaryTone | undefined { - if (index === 0 || baseline == null || value === baseline) +function getSummaryTone(index: number, value: number | null, baseline: number | null | undefined): SummaryTone | undefined { + if (index === 0 || value == null || baseline == null || value === baseline) return undefined return value > baseline ? 'increase' : 'decrease' } @@ -662,12 +675,12 @@ function getPluginSummaryStats(index: number, session: NormalizedSessionCompareC } } -function sumCompareSide(items: T[] | undefined, index: number, getPrevious: (item: T) => number, getCurrent: (item: T) => number) { - return (items ?? []).reduce((total, item) => total + (index === 0 ? getPrevious(item) : getCurrent(item)), 0) +function sumCompareSide(items: T[] | undefined, index: number, getPrevious: (item: T) => number | null, getCurrent: (item: T) => number | null) { + return sumMetrics((items ?? []).map(item => index === 0 ? getPrevious(item) : getCurrent(item))) } function sumDelta(rows: SplitDiffRow[]) { - return rows.reduce((total, row) => total + row.delta, 0) + return sumMetrics(rows.map(row => row.delta)) } @@ -712,7 +725,7 @@ function sumDelta(rows: SplitDiffRow[]) { -
+
-