@@ -11,62 +11,14 @@ definePageMeta({
1111 alias: [' /package/:package(.*)*' ],
1212})
1313
14- const route = useRoute (' package' )
15-
1614const router = useRouter ()
1715
18- // Parse package name and optional version from URL
19- // Patterns:
20- // /nuxt → packageName: "nuxt", requestedVersion: null
21- // /nuxt/v/4.2.0 → packageName: "nuxt", requestedVersion: "4.2.0"
22- // /@nuxt/kit → packageName: "@nuxt/kit", requestedVersion: null
23- // /@nuxt/kit/v/1.0.0 → packageName: "@nuxt/kit", requestedVersion: "1.0.0"
24- // /axios@1.13.3 → packageName: "axios", requestedVersion: "1.13.3"
25- // /@nuxt/kit@1.0.0 → packageName: "@nuxt/kit", requestedVersion: "1.0.0"
26- const parsedRoute = computed (() => {
27- const segments = route .params .package || []
28-
29- // Find the /v/ separator for version
30- const vIndex = segments .indexOf (' v' )
31- if (vIndex !== - 1 && vIndex < segments .length - 1 ) {
32- return {
33- packageName: segments .slice (0 , vIndex ).join (' /' ),
34- requestedVersion: segments .slice (vIndex + 1 ).join (' /' ),
35- }
36- }
37-
38- // Parse @ versioned package
39- const fullPath = segments .join (' /' )
40- const versionMatch = fullPath .match (/ ^ (@[^ /] + \/ [^ /] + | [^ /] + )@([^ /] + )$ / )
41- if (versionMatch ) {
42- const [, packageName, requestedVersion] = versionMatch as [string , string , string ]
43- return {
44- packageName ,
45- requestedVersion ,
46- }
47- }
48-
49- return {
50- packageName: fullPath ,
51- requestedVersion: null as string | null ,
52- }
53- })
54-
55- const packageName = computed (() => parsedRoute .value .packageName )
56- const requestedVersion = computed (() => parsedRoute .value .requestedVersion )
16+ const { packageName, requestedVersion, orgName } = usePackageRoute ()
5717
5818if (import .meta .server ) {
5919 assertValidPackageName (packageName .value )
6020}
6121
62- // Extract org name from scoped package (e.g., "@nuxt/kit" -> "nuxt")
63- const orgName = computed (() => {
64- const name = packageName .value
65- if (! name .startsWith (' @' )) return null
66- const match = name .match (/ ^ @([^ /] + )\/ / )
67- return match ? match [1 ] : null
68- })
69-
7022const { data : downloads } = usePackageDownloads (packageName , ' last-week' )
7123const { data : weeklyDownloads } = usePackageWeeklyDownloadEvolution (packageName , { weeks: 52 })
7224
@@ -112,17 +64,7 @@ const {
11264)
11365onMounted (() => fetchInstallSize ())
11466
115- const sizeTooltip = computed (() => {
116- const chunks = [
117- displayVersion .value &&
118- displayVersion .value .dist .unpackedSize &&
119- ` ${formatBytes (displayVersion .value .dist .unpackedSize )} unpacked size (this package) ` ,
120- installSize .value &&
121- installSize .value .dependencyCount &&
122- ` ${formatBytes (installSize .value .totalSize )} total unpacked size (including all ${installSize .value .dependencyCount } dependencies for linux-x64) ` ,
123- ]
124- return chunks .filter (Boolean ).join (' \n ' )
125- })
67+ const { data : packageAnalysis } = usePackageAnalysis (packageName , requestedVersion )
12668
12769const { data : pkg, status, error } = await usePackage (packageName , requestedVersion )
12870const resolvedVersion = computed (() => pkg .value ?.resolvedVersion ?? null )
@@ -164,6 +106,18 @@ const deprecationNotice = computed(() => {
164106 return { type: ' version' as const , message: displayVersion .value .deprecated }
165107})
166108
109+ const sizeTooltip = computed (() => {
110+ const chunks = [
111+ displayVersion .value &&
112+ displayVersion .value .dist .unpackedSize &&
113+ ` ${formatBytes (displayVersion .value .dist .unpackedSize )} unpacked size (this package) ` ,
114+ installSize .value &&
115+ installSize .value .dependencyCount &&
116+ ` ${formatBytes (installSize .value .totalSize )} total unpacked size (including all ${installSize .value .dependencyCount } dependencies for linux-x64) ` ,
117+ ]
118+ return chunks .filter (Boolean ).join (' \n ' )
119+ })
120+
167121const hasDependencies = computed (() => {
168122 if (! displayVersion .value ) return false
169123 const deps = displayVersion .value .dependencies
@@ -252,12 +206,6 @@ function hasProvenance(version: PackumentVersion | null): boolean {
252206 return !! dist .attestations
253207}
254208
255- const selectedPM = useSelectedPackageManager ()
256- const { settings } = useSettings ()
257-
258- // Fetch package analysis for @types info
259- const { data : packageAnalysis } = usePackageAnalysis (packageName , requestedVersion )
260-
261209// Get @types package name if available (non-deprecated)
262210const typesPackageName = computed (() => {
263211 if (! packageAnalysis .value ) return null
@@ -266,76 +214,14 @@ const typesPackageName = computed(() => {
266214 return packageAnalysis .value .types .packageName
267215})
268216
269- // Check if we should show @types in install command
270- const showTypesInInstall = computed (() => {
271- return settings .value .includeTypesInInstall && typesPackageName .value
272- })
273-
274- const installCommandParts = computed (() => {
275- if (! pkg .value ) return []
276- return getInstallCommandParts ({
277- packageName: pkg .value .name ,
278- packageManager: selectedPM .value ,
279- version: requestedVersion .value ,
280- jsrInfo: jsrInfo .value ,
281- })
282- })
283-
284- const installCommand = computed (() => {
285- if (! pkg .value ) return ' '
286- return getInstallCommand ({
287- packageName: pkg .value .name ,
288- packageManager: selectedPM .value ,
289- version: requestedVersion .value ,
290- jsrInfo: jsrInfo .value ,
291- })
292- })
293-
294- // Get the dev dependency flag for the selected package manager
295- function getDevFlag(pmId : string ): string {
296- // bun uses lowercase -d, all others use -D
297- return pmId === ' bun' ? ' -d' : ' -D'
298- }
299-
300- // @types install command parts (for display)
301- const typesInstallCommandParts = computed (() => {
302- if (! typesPackageName .value ) return []
303- const pm = packageManagers .find (p => p .id === selectedPM .value )
304- if (! pm ) return []
305-
306- const devFlag = getDevFlag (selectedPM .value )
307- const pkgSpec =
308- selectedPM .value === ' deno' ? ` npm:${typesPackageName .value } ` : typesPackageName .value
309-
310- return [pm .label , pm .action , devFlag , pkgSpec ]
311- })
312-
313- // Full install command including @types (for copying)
314- const fullInstallCommand = computed (() => {
315- if (! installCommand .value ) return ' '
316- if (! showTypesInInstall .value || ! typesPackageName .value ) {
317- return installCommand .value
318- }
319-
320- const pm = packageManagers .find (p => p .id === selectedPM .value )
321- if (! pm ) return installCommand .value
322-
323- const devFlag = getDevFlag (selectedPM .value )
324- const pkgSpec =
325- selectedPM .value === ' deno' ? ` npm:${typesPackageName .value } ` : typesPackageName .value
326-
327- // Use semicolon to separate commands
328- return ` ${installCommand .value }; ${pm .label } ${pm .action } ${devFlag } ${pkgSpec } `
329- })
330-
331- // Copy install command
332- const copied = ref (false )
333- async function copyInstallCommand() {
334- if (! fullInstallCommand .value ) return
335- await navigator .clipboard .writeText (fullInstallCommand .value )
336- copied .value = true
337- setTimeout (() => (copied .value = false ), 2000 )
338- }
217+ const {
218+ selectedPM,
219+ installCommandParts,
220+ typesInstallCommandParts,
221+ showTypesInInstall,
222+ copied,
223+ copyInstallCommand,
224+ } = useInstallCommand (packageName , requestedVersion , jsrInfo , typesPackageName )
339225
340226// Expandable description
341227const descriptionExpanded = ref (false )
0 commit comments