Skip to content

Commit bd6e330

Browse files
committed
perf: slim down packument in payload
1 parent ef7139b commit bd6e330

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

app/composables/useNpmRegistry.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type {
22
Packument,
3+
PackumentVersion,
4+
SlimPackument,
35
NpmSearchResponse,
46
NpmDownloadCount,
57
NpmDownloadRange,
@@ -66,12 +68,78 @@ function encodePackageName(name: string): string {
6668
return encodeURIComponent(name)
6769
}
6870

71+
/** Maximum number of versions to include in the client payload */
72+
const MAX_VERSIONS = 20
73+
74+
/**
75+
* Transform a full Packument into a slimmed version for client-side use.
76+
* Reduces payload size by:
77+
* - Removing readme (fetched separately)
78+
* - Limiting versions to recent MAX_VERSIONS
79+
* - Stripping unnecessary fields from version objects
80+
*/
81+
function transformPackument(pkg: Packument): SlimPackument {
82+
// Sort versions by publish time (newest first)
83+
const sortedVersionKeys = Object.keys(pkg.versions)
84+
.filter(v => pkg.time[v]) // Only versions with timestamps
85+
.sort((a, b) => {
86+
const timeA = pkg.time[a]
87+
const timeB = pkg.time[b]
88+
if (!timeA || !timeB) return 0
89+
return new Date(timeB).getTime() - new Date(timeA).getTime()
90+
})
91+
.slice(0, MAX_VERSIONS)
92+
93+
// Always include the latest dist-tag version even if not in top MAX_VERSIONS
94+
const latestTag = pkg['dist-tags']?.latest
95+
if (latestTag && !sortedVersionKeys.includes(latestTag)) {
96+
sortedVersionKeys.push(latestTag)
97+
}
98+
99+
// Build filtered versions object
100+
const filteredVersions: Record<string, PackumentVersion> = {}
101+
for (const v of sortedVersionKeys) {
102+
const version = pkg.versions[v]
103+
if (version) {
104+
// Strip readme and scripts from each version to reduce size
105+
const { readme: _readme, scripts: _scripts, ...slimVersion } = version
106+
filteredVersions[v] = slimVersion as PackumentVersion
107+
}
108+
}
109+
110+
// Build filtered time object (only for included versions)
111+
const filteredTime: Record<string, string> = {}
112+
if (pkg.time.modified) filteredTime.modified = pkg.time.modified
113+
if (pkg.time.created) filteredTime.created = pkg.time.created
114+
for (const v of sortedVersionKeys) {
115+
if (pkg.time[v]) filteredTime[v] = pkg.time[v]
116+
}
117+
118+
return {
119+
'_id': pkg._id,
120+
'_rev': pkg._rev,
121+
'name': pkg.name,
122+
'description': pkg.description,
123+
'dist-tags': pkg['dist-tags'],
124+
'time': filteredTime,
125+
'maintainers': pkg.maintainers,
126+
'author': pkg.author,
127+
'license': pkg.license,
128+
'homepage': pkg.homepage,
129+
'keywords': pkg.keywords,
130+
'repository': pkg.repository,
131+
'bugs': pkg.bugs,
132+
'versions': filteredVersions,
133+
}
134+
}
135+
69136
export function usePackage(name: MaybeRefOrGetter<string>) {
70137
const registry = useNpmRegistry()
71138

72139
return useLazyAsyncData(
73140
() => `package:${toValue(name)}`,
74141
() => registry.fetchPackage(toValue(name)),
142+
{ transform: transformPackument },
75143
)
76144
}
77145

shared/types/npm-registry.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,32 @@
99
// Re-export official npm types for packument/manifest
1010
export type { Packument, PackumentVersion, Manifest, ManifestVersion, PackageJSON } from '@npm/types'
1111

12+
/**
13+
* Slimmed down Packument for client-side use.
14+
* Strips unnecessary fields to reduce payload size.
15+
* - readme removed (fetched separately)
16+
* - versions limited to recent 20
17+
* - time limited to recent 20 versions
18+
*/
19+
export interface SlimPackument {
20+
'_id': string
21+
'_rev'?: string
22+
'name': string
23+
'description'?: string
24+
'dist-tags': { latest?: string } & Record<string, string>
25+
/** Only includes time for recent versions + modified/created */
26+
'time': { modified?: string, created?: string } & Record<string, string>
27+
'maintainers'?: NpmPerson[]
28+
'author'?: NpmPerson
29+
'license'?: string
30+
'homepage'?: string
31+
'keywords'?: string[]
32+
'repository'?: { type?: string, url?: string, directory?: string }
33+
'bugs'?: { url?: string, email?: string }
34+
/** Only includes recent 20 versions */
35+
'versions': Record<string, import('@npm/types').PackumentVersion>
36+
}
37+
1238
/**
1339
* Person/contact type extracted from @npm/types Contact interface
1440
* Used for maintainers, authors, publishers

0 commit comments

Comments
 (0)