Skip to content

Commit af81566

Browse files
committed
feat: celebrate size decreases
This adds a small message when a package decreases in size or dependency count beyond our thresholds, only if it had no increases. e.g. +1 deps, -200KB = no celebration, +0 deps, -200KB = celebration, etc
1 parent 3c3bfeb commit af81566

5 files changed

Lines changed: 98 additions & 4 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<script setup lang="ts">
2+
import type { InstallSizeDiff } from '~/composables/useInstallSizeDiff'
3+
4+
const props = defineProps<{
5+
diff: InstallSizeDiff
6+
}>()
7+
8+
const bytesFormatter = useBytesFormatter()
9+
const numberFormatter = useNumberFormatter()
10+
11+
const sizePercent = computed(() => Math.round(Math.abs(props.diff.sizeRatio) * 100))
12+
const sizeDecreaseAbs = computed(() => Math.abs(props.diff.sizeIncrease))
13+
const depDecreaseAbs = computed(() => Math.abs(props.diff.depDiff))
14+
</script>
15+
16+
<template>
17+
<div
18+
class="border border-emerald-600/40 bg-emerald-500/10 rounded-lg px-3 py-2 text-base text-emerald-800 dark:text-emerald-400"
19+
>
20+
<h2 class="font-medium mb-1 flex items-center gap-2">
21+
<span class="i-lucide:trending-down w-4 h-4" aria-hidden="true" />
22+
<span>
23+
{{
24+
diff.sizeThresholdExceeded && diff.depThresholdExceeded
25+
? $t('package.size_decrease.title_both', { version: diff.comparisonVersion })
26+
: diff.sizeThresholdExceeded
27+
? $t('package.size_decrease.title_size', { version: diff.comparisonVersion })
28+
: $t('package.size_decrease.title_deps', { version: diff.comparisonVersion })
29+
}}
30+
</span>
31+
<span aria-hidden="true">🎉</span>
32+
</h2>
33+
<p class="text-sm m-0 mt-1">
34+
<i18n-t v-if="diff.sizeThresholdExceeded" keypath="package.size_decrease.size" scope="global">
35+
<template #percent
36+
><strong>{{ sizePercent }}%</strong></template
37+
>
38+
<template #size
39+
><strong>{{ bytesFormatter.format(sizeDecreaseAbs) }}</strong></template
40+
>
41+
</i18n-t>
42+
<template v-if="diff.sizeThresholdExceeded && diff.depThresholdExceeded"> · </template>
43+
<i18n-t v-if="diff.depThresholdExceeded" keypath="package.size_decrease.deps" scope="global">
44+
<template #count
45+
><strong>−{{ numberFormatter.format(depDecreaseAbs) }}</strong></template
46+
>
47+
</i18n-t>
48+
</p>
49+
</div>
50+
</template>

app/composables/useInstallSizeDiff.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { compare, prerelease, valid } from 'semver'
22

33
export interface InstallSizeDiff {
4+
direction: 'increase' | 'decrease'
45
comparisonVersion: string
56
sizeRatio: number
67
sizeIncrease: number
@@ -15,6 +16,8 @@ export interface InstallSizeDiff {
1516

1617
const SIZE_INCREASE_THRESHOLD = 0.25
1718
const DEP_INCREASE_THRESHOLD = 5
19+
const SIZE_DECREASE_THRESHOLD = 0.2
20+
const DEP_DECREASE_THRESHOLD = 3
1821

1922
function getComparisonVersion(pkg: SlimPackument, resolvedVersion: string): string | null {
2023
const isCurrentPrerelease = prerelease(resolvedVersion) !== null
@@ -91,12 +94,23 @@ export function useInstallSizeDiff(
9194
previous.totalSize > 0 ? (current.totalSize - previous.totalSize) / previous.totalSize : 0
9295
const depDiff = current.dependencyCount - previous.dependencyCount
9396

94-
const sizeThresholdExceeded = sizeRatio > SIZE_INCREASE_THRESHOLD
95-
const depThresholdExceeded = depDiff > DEP_INCREASE_THRESHOLD
97+
const increaseSize = sizeRatio > SIZE_INCREASE_THRESHOLD
98+
const increaseDeps = depDiff > DEP_INCREASE_THRESHOLD
99+
const decreaseSize = sizeRatio < -SIZE_DECREASE_THRESHOLD
100+
const decreaseDeps = depDiff < -DEP_DECREASE_THRESHOLD
96101

97-
if (!sizeThresholdExceeded && !depThresholdExceeded) return null
102+
const isIncrease = increaseSize || increaseDeps
103+
const isDecrease =
104+
!isIncrease && sizeRatio <= 0 && depDiff <= 0 && (decreaseSize || decreaseDeps)
105+
106+
if (!isIncrease && !isDecrease) return null
107+
108+
const direction: 'increase' | 'decrease' = isIncrease ? 'increase' : 'decrease'
109+
const sizeThresholdExceeded = isIncrease ? increaseSize : decreaseSize
110+
const depThresholdExceeded = isIncrease ? increaseDeps : decreaseDeps
98111

99112
return {
113+
direction,
100114
comparisonVersion: cv,
101115
sizeRatio,
102116
sizeIncrease: current.totalSize - previous.totalSize,

app/pages/package/[[org]]/[name].vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,9 @@ const showSkeleton = shallowRef(false)
919919
:replacement="moduleReplacement.replacement"
920920
/>
921921
<!-- Size / dependency increase notice -->
922-
<PackageSizeIncrease v-if="sizeDiff" :diff="sizeDiff" />
922+
<PackageSizeIncrease v-if="sizeDiff?.direction === 'increase'" :diff="sizeDiff" />
923+
<!-- Size / dependency decrease celebration -->
924+
<PackageSizeDecrease v-else-if="sizeDiff?.direction === 'decrease'" :diff="sizeDiff" />
923925
<!-- Vulnerability scan -->
924926
<ClientOnly>
925927
<PackageVulnerabilityTree

i18n/locales/en.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,13 @@
384384
"size": "Install size increased by {percent} ({size} larger)",
385385
"deps": "{count} more dependencies"
386386
},
387+
"size_decrease": {
388+
"title_size": "Package size decreased since v{version}!",
389+
"title_deps": "Dependency count decreased since v{version}!",
390+
"title_both": "Package size and dependency count decreased since v{version}!",
391+
"size": "Install size reduced by {percent} ({size} smaller)",
392+
"deps": "{count} fewer dependencies"
393+
},
387394
"replacement": {
388395
"title": "You might not need this dependency.",
389396
"example": "Example:",

i18n/schema.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,27 @@
11561156
},
11571157
"additionalProperties": false
11581158
},
1159+
"size_decrease": {
1160+
"type": "object",
1161+
"properties": {
1162+
"title_size": {
1163+
"type": "string"
1164+
},
1165+
"title_deps": {
1166+
"type": "string"
1167+
},
1168+
"title_both": {
1169+
"type": "string"
1170+
},
1171+
"size": {
1172+
"type": "string"
1173+
},
1174+
"deps": {
1175+
"type": "string"
1176+
}
1177+
},
1178+
"additionalProperties": false
1179+
},
11591180
"replacement": {
11601181
"type": "object",
11611182
"properties": {

0 commit comments

Comments
 (0)