@@ -70,201 +70,17 @@ const sortedOptionalDependencies = computed(() => {
7070})
7171
7272// Fetch size information for dependencies that require it
73- const { data : sizereqData, pending : sizereqLoading } = await useAsyncData (
74- ` sizes:${props .packageName }:${props .version } ` ,
75- async (_app , { signal }) => {
76- const entries = sortedDependencies .value
77-
78- const results = await Promise .all (
79- entries .map <
80- Promise <
81- { kind: ' success' ; packageSize : InstallSizeResult } | { kind: ' error' ; error : NuxtError }
82- >
83- > (async ([name , version ]) => {
84- try {
85- const { data : resolvedVersion, error } = await useResolvedVersion (name , version )
86-
87- if (error .value || ! resolvedVersion .value ) return { kind: ' error' , error: error .value ! }
88-
89- return {
90- kind: ' success' ,
91- packageSize: await $fetch <InstallSizeResult >(
92- ` /api/registry/install-size/${name }/v/${encodeURIComponent (resolvedVersion .value )} ` ,
93- { signal },
94- ),
95- }
96- } catch (err ) {
97- return { kind: ' error' , error: (err as Ref <NuxtError >)?.value }
98- }
99- }),
100- )
101-
102- return results .reduce (
103- (acc , curr ) => {
104- if (curr .kind === ' error' ) return acc
105- acc [curr .packageSize .package ] = curr
106- return acc
107- },
108- {} as Record <
109- string ,
110- { kind: ' success' ; packageSize: InstallSizeResult } | { kind: ' error' ; error: NuxtError }
111- >,
112- )
113- },
114- {
115- watch: [sortedDependencies ],
116- server: false ,
117- },
73+ const { data : sizereqData, pending : sizereqLoading } = usePackageDependencySizes (
74+ () => props .packageName ,
75+ () => props .version ,
76+ () => props .dependencies ,
11877)
11978
120- // Minimum percentage to be shown as an individual slice
121- const THRESHOLD_PERCENT = 2
122-
123- type Sizereq = {
124- info: InstallSizeResult
125- bundled: boolean
126- percent: number
127- error: NuxtError | null
128- }
129-
130- // Process dependencies for size visualization
131- const sortedSizereqDependecies = computed (() => {
132- if (! props .packageSize ?.totalSize || ! props .packageSize .dependencies ) {
133- return { visible: [], others: [], totalOthersSize: 0 , othersPercentage: 0 }
134- }
135-
136- const allMapped = props .packageSize .dependencies .map (depSize => {
137- let bundled: boolean = false
138- switch (typeof props .bundledDependencies ) {
139- case ' boolean' :
140- bundled = props .bundledDependencies
141- break
142- case ' object' :
143- bundled = props .bundledDependencies .some (name => name === depSize .name )
144- break
145- }
146- const percent = props .packageSize ? (depSize .size / props .packageSize .totalSize ) * 100 : 0
147- const serverData = sizereqData .value ?.[depSize .name ]
148- const error = serverData ?.kind === ' error' ? serverData .error : null
149- return {
150- info:
151- serverData ?.kind === ' success' && serverData .packageSize
152- ? {
153- package: depSize .name ,
154- version: depSize .version ,
155- totalSize: serverData .packageSize .totalSize ,
156- selfSize: serverData .packageSize .selfSize ,
157- }
158- : {
159- package: depSize .name ,
160- version: depSize .version ,
161- totalSize: depSize .size ,
162- selfSize: depSize .size ,
163- },
164- error ,
165- bundled ,
166- percent ,
167- } as Sizereq
168- })
169-
170- const visible: Sizereq [] = []
171- const others: Sizereq [] = []
172-
173- for (const dep of allMapped ) {
174- const percentage = (dep .info .selfSize / props .packageSize .totalSize ) * 100
175- if (percentage >= THRESHOLD_PERCENT ) {
176- visible .push ({ ... dep , percent: percentage })
177- } else {
178- others .push (dep )
179- }
180- }
181-
182- const othersSelfSize = others .reduce ((acc , d ) => acc + d .info .selfSize , 0 )
183- const othersPercentage = (othersSelfSize / props .packageSize .totalSize ) * 100
184-
185- // if (others.length === 1) {
186- // visible.push(others[0]!)
187- // others.length = 0
188- // visible.sort((a, b) => b.info.totalSize - a.info.totalSize)
189- // } else if (others.length > 1 && othersPercentage < THRESHOLD_PERCENT) {
190- // visible.push(...others)
191- // others.length = 0
192- // visible.sort((a, b) => b.info.totalSize - a.info.totalSize)
193- // }
194-
195- return { visible , others , totalOthersSize: othersSelfSize , othersPercentage }
196- })
197-
198- const othersTooltip = computed (() => {
199- const others = sortedSizereqDependecies .value .others
200- if (others .length === 0 ) return ' '
201-
202- const MAX_VISIBLE_IN_TOOLTIP = 0
203- const visiblePart = others .slice (0 , MAX_VISIBLE_IN_TOOLTIP )
204- const remainingCount = others .length - MAX_VISIBLE_IN_TOOLTIP
205-
206- const lines = [
207- bytesFormatter .format (sortedSizereqDependecies .value .totalOthersSize ),
208- numberFormatter .value .format (sortedSizereqDependecies .value .othersPercentage ),
209- ' ' ,
210- ... visiblePart .flatMap (size => [size .info .package , getDepSizeTooltipText (size ), ' ' ]),
211- ]
212-
213- if (remainingCount > 0 ) {
214- lines .push (t (' package.size_increase.deps' , { count: remainingCount }))
215- }
216-
217- return lines .join (' \n ' )
218- })
219-
220- const selfSizeWidth = computed (() => {
221- if (! props .packageSize ?.selfSize || ! props .packageSize ?.totalSize ) return 0
222- return (props .packageSize .selfSize / props .packageSize .totalSize ) * 100
223- })
224-
225- const remainingWidth = computed (() => {
226- const total = props .packageSize ?.totalSize
227- if (! total ) return 100
228-
229- const self = props .packageSize .selfSize || 0
230- const depsSum = [
231- ... sortedSizereqDependecies .value .visible ,
232- ... sortedSizereqDependecies .value .others ,
233- ].reduce ((acc , d ) => acc + d .info .selfSize , 0 )
234-
235- const width = ((total - (self + depsSum )) / total ) * 100
236- return Math .max (0 , width )
237- })
238-
239- // Get dependency size tooltip
240- function getDepSizeTooltip(dep : string ): string | undefined {
241- const size = [
242- ... sortedSizereqDependecies .value .visible ,
243- ... sortedSizereqDependecies .value .others ,
244- ].find (d => d .info .package === dep )
245- return size && getDepSizeTooltipText (size )
246- }
247-
248- function getDepSizeTooltipText(size : Sizereq ): string {
249- const packageSize = size ?.error ? undefined : size ?.info
250- const percent = size ?.percent
251- return [
252- size ?.error ?.message ,
253- percent && numberFormatter .value .format (percent ),
254- packageSize &&
255- packageSize ?.totalSize !== packageSize ?.selfSize &&
256- t (' package.stats.size_tooltip.unpacked' , {
257- size: bytesFormatter .format (packageSize .selfSize ! ),
258- }),
259- packageSize ?.totalSize &&
260- t (' package.stats.size_tooltip.total' , {
261- count: packageSize .dependencyCount ,
262- size: bytesFormatter .format (packageSize .totalSize ),
263- }),
264- ]
265- .filter (Boolean )
266- .join (' \n ' )
267- }
79+ const { getTooltipText : getDepSizeTooltip } = usePackageDependencySizeTooltip (
80+ sizereqData ,
81+ () => props .packageSize ,
82+ t ,
83+ )
26884
26985// Get version tooltip
27086function getDepVersionTooltip(dep : string , version : string ) {
@@ -313,7 +129,7 @@ const bytesFormatter = useBytesFormatter()
313129 v-if =" sortedDependencies.length > 0"
314130 id =" dependencies"
315131 :title ="
316- $ t(
132+ t(
317133 'package.dependencies.title',
318134 {
319135 count: numberFormatter.format(sortedDependencies.length),
@@ -322,46 +138,13 @@ const bytesFormatter = useBytesFormatter()
322138 )
323139 "
324140 >
325- <div class =" gap-0.5 flex flex-row h-6 w-full bg-fg-muted/10 overflow-hidden rounded-md" >
326- <TooltipApp
327- v-if =" selfSizeWidth > 0"
328- :text ="
329- t('package.stats.size_tooltip.unpacked', {
330- size: bytesFormatter.format(props.packageSize?.selfSize || 0),
331- })
332- "
333- class =" h-full bg-accent"
334- :style =" { width: selfSizeWidth + '%' }"
335- />
336-
337- <template v-for =" dep in sortedSizereqDependecies .visible " :key =" dep .info .package " >
338- <TooltipApp
339- :text =" `${dep.info.package}\n${getDepSizeTooltip(dep.info.package)}`"
340- class =" h-full"
341- :class =" dep.bundled ? 'bg-accent' : 'bg-fg'"
342- :style =" { width: dep.percent + '%' }"
343- >
344- <RouterLink
345- :to =" packageRoute(dep.info.package, dep.info.version)"
346- class =" block w-full h-full"
347- />
348- </TooltipApp >
349- </template >
350-
351- <TooltipApp
352- v-if =" sortedSizereqDependecies.others.length > 0"
353- :text =" othersTooltip"
354- class =" h-full bg-fg flex items-center justify-center"
355- :style =" { width: sortedSizereqDependecies.othersPercentage + '%' }"
356- >
357- <span class =" i-lucide:layers-2 w-3 h-3 text-bg" aria-hidden =" true" />
358- </TooltipApp >
359-
360- <div
361- v-if =" remainingWidth > 0"
362- class =" h-full bg-bg-elevated animate-skeleton-pulse flex-1"
363- />
364- </div >
141+ <PackageSizeBar
142+ :package-name =" props.packageName"
143+ :version =" props.version"
144+ :package-size =" props.packageSize"
145+ :dependencies =" props.dependencies"
146+ :bundled-dependencies =" props.bundledDependencies"
147+ />
365148 <ul class =" space-y-1 list-none m-0" :aria-label =" $t('package.dependencies.list_label')" >
366149 <li
367150 v-for =" [dep, version] in visibleDeps"
@@ -376,12 +159,12 @@ const bytesFormatter = useBytesFormatter()
376159 v-if =" outdatedDeps[dep]"
377160 class =" shrink-0"
378161 :class =" getVersionClass(outdatedDeps[dep])"
379- :text =" getOutdatedTooltip(outdatedDeps[dep], $ t)"
162+ :text =" getOutdatedTooltip(outdatedDeps[dep], t)"
380163 >
381164 <button
382165 type =" button"
383166 class =" inline-flex items-center justify-center p-2 -m-2"
384- :aria-label =" getOutdatedTooltip(outdatedDeps[dep], $ t)"
167+ :aria-label =" getOutdatedTooltip(outdatedDeps[dep], t)"
385168 >
386169 <span class =" i-lucide:circle-alert w-3 h-3" aria-hidden =" true" />
387170 </button >
@@ -451,7 +234,7 @@ const bytesFormatter = useBytesFormatter()
451234 </button >
452235 </TooltipApp >
453236 <span v-if =" outdatedDeps[dep]" class =" sr-only" >
454- ({{ getOutdatedTooltip(outdatedDeps[dep], $ t) }})
237+ ({{ getOutdatedTooltip(outdatedDeps[dep], t) }})
455238 </span >
456239 <span v-if =" getVulnerableDepInfo(dep)" class =" sr-only" >
457240 ({{
@@ -470,7 +253,7 @@ const bytesFormatter = useBytesFormatter()
470253 @click =" expandDeps"
471254 >
472255 {{
473- $ t(
256+ t(
474257 'package.dependencies.show_all',
475258 {
476259 count: numberFormatter.format(sortedDependencies.length),
@@ -525,7 +308,7 @@ const bytesFormatter = useBytesFormatter()
525308 @click =" expandPeerDeps"
526309 >
527310 {{
528- $ t(
311+ t(
529312 'package.peer_dependencies.show_all',
530313 {
531314 count: numberFormatter.format(sortedPeerDependencies.length),
@@ -541,7 +324,7 @@ const bytesFormatter = useBytesFormatter()
541324 v-if =" sortedOptionalDependencies.length > 0"
542325 id =" optional-dependencies"
543326 :title ="
544- $ t(
327+ t(
545328 'package.optional_dependencies.title',
546329 {
547330 count: numberFormatter.format(sortedOptionalDependencies.length),
@@ -579,7 +362,7 @@ const bytesFormatter = useBytesFormatter()
579362 @click =" expandOptionalDeps"
580363 >
581364 {{
582- $ t(
365+ t(
583366 'package.optional_dependencies.show_all',
584367 {
585368 count: numberFormatter.format(sortedOptionalDependencies.length),
0 commit comments