diff --git a/app/components/DepsStats/DependencyStatsPanel.vue b/app/components/DepsStats/DependencyStatsPanel.vue index 3b7291a0ed..7dd1cacdea 100644 --- a/app/components/DepsStats/DependencyStatsPanel.vue +++ b/app/components/DepsStats/DependencyStatsPanel.vue @@ -34,13 +34,16 @@ const { data: installSize, execute: fetchInstallSize } = useLazyFetch { - if (version) fetchInstallSize() - }, - { immediate: true }, -) +// Client-only: install size walks the whole dependency tree, so never block SSR on it. +if (import.meta.client) { + watch( + resolvedVersion, + version => { + if (version) fetchInstallSize() + }, + { immediate: true }, + ) +} const { diff: sizeDiff } = useInstallSizeDiff( () => props.packageName, diff --git a/app/composables/useDependencyAnalysis.ts b/app/composables/useDependencyAnalysis.ts index d8eee606a2..5de41ee261 100644 --- a/app/composables/useDependencyAnalysis.ts +++ b/app/composables/useDependencyAnalysis.ts @@ -2,6 +2,13 @@ * Shared composable for dependency analysis data (vulnerabilities, deprecated packages). * Fetches once and caches the result so multiple components can use it. * Before: useVulnerabilityTree - but now we use this for both vulnerabilities and deprecated packages. + * + * Client-only and lazy: resolving the whole transitive dependency graph (one packument download + * per dependency) plus OSV queries is far too slow to block the package page's server render. The + * data only drives the vulnerability count and the vulnerability/deprecated trees, none of which + * need to be in the server HTML. + * + * `useFetch` dedupes by key (the request URL), so all consumers share the same request/result. */ export function useDependencyAnalysis( packageName: MaybeRefOrGetter, @@ -10,5 +17,9 @@ export function useDependencyAnalysis( return useFetch( () => `/api/registry/vulnerabilities/${encodePackageName(toValue(packageName))}/v/${toValue(version)}`, + { + server: false, + lazy: true, + }, ) } diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index 1cb7073cb8..ac88e3c315 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -128,16 +128,19 @@ const { }, ) -// Trigger fetch only when we have the real resolved version -watch( - [resolvedVersion, resolvedStatus], - ([version, status]) => { - if (version && status === 'success') { - fetchInstallSize() - } - }, - { immediate: true }, -) +// Trigger fetch only when we have the real resolved version. +// Client-only: install size walks the whole dependency tree, so never block SSR on it. +if (import.meta.client) { + watch( + [resolvedVersion, resolvedStatus], + ([version, status]) => { + if (version && status === 'success') { + fetchInstallSize() + } + }, + { immediate: true }, + ) +} const { data: skillsData } = useLazyFetch( () => { @@ -672,23 +675,28 @@ const showSkeleton = shallowRef(false) - - - +