Skip to content

Commit c177026

Browse files
perf(server-bundle): discover collections via directory listing (#501)
Co-authored-by: Sébastien Chopin <[email protected]>
1 parent a744c65 commit c177026

1 file changed

Lines changed: 50 additions & 9 deletions

File tree

src/collections.ts

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,58 @@ async function parseCustomCollection(
127127

128128
export async function discoverInstalledCollections(nuxt: Nuxt): Promise<ServerBundleOptions['collections']> {
129129
const paths = getResolvePaths(nuxt)
130-
const fullCollectionInstalled = hasFullCollection(nuxt)
131-
const collections = fullCollectionInstalled
132-
? collectionNames
133-
: collectionNames.filter(collection => isPackageExists('@iconify-json/' + collection, { paths }))
134-
if (fullCollectionInstalled)
135-
logger.success(`Nuxt Icon discovered local-installed ${collections.length} collections (@iconify/json)`)
136-
else if (collections.length)
137-
logger.success(`Nuxt Icon discovered local-installed ${collections.length} collections:`, collections.join(', '))
138130

139-
if (fullCollectionInstalled)
131+
if (hasFullCollection(nuxt)) {
132+
logger.success(`Nuxt Icon discovered local-installed ${collectionNames.length} collections (@iconify/json)`)
140133
logger.warn('Currently all iconify collections are included in the bundle, which might be inefficient, consider explicit name the collections you use in the `icon.serverBundle.collections` option')
134+
return collectionNames
135+
}
136+
137+
// Find which `@iconify-json/*` packages are installed;
138+
// Special for Yarn PnP, which does not have a `node_modules` folder.
139+
const found = new Set<string>()
140+
if (process.versions.pnp) {
141+
for (const collection of collectionNames) {
142+
if (isPackageExists('@iconify-json/' + collection, { paths }))
143+
found.add(collection)
144+
}
145+
}
146+
else {
147+
await Promise.all(iconifyScopeDirs(paths).map(async (scope) => {
148+
const entries = await fs.readdir(scope).catch(() => [] as string[])
149+
await Promise.all(entries.map(async (name) => {
150+
if (name.startsWith('.'))
151+
return
152+
// A real Iconify collection package ships an `icons.json`.
153+
const hasIconsJson = await fs.access(join(scope, name, 'icons.json')).then(() => true, () => false)
154+
if (hasIconsJson)
155+
found.add(name)
156+
}))
157+
}))
158+
}
159+
160+
const collections = collectionNames.filter(collection => found.has(collection))
161+
if (collections.length)
162+
logger.success(`Nuxt Icon discovered local-installed ${collections.length} collections:`, collections.join(', '))
141163

142164
return collections
143165
}
166+
167+
/**
168+
* Returns the `@iconify-json` scope directory inside every `node_modules`,
169+
* deduped, walking up the tree like the Node resolver.
170+
*/
171+
function iconifyScopeDirs(paths: string[]): string[] {
172+
const dirs = new Set<string>()
173+
for (const base of paths) {
174+
let dir = base
175+
while (true) {
176+
dirs.add(join(dir, 'node_modules', '@iconify-json'))
177+
const parent = join(dir, '..')
178+
if (parent === dir)
179+
break
180+
dir = parent
181+
}
182+
}
183+
return [...dirs]
184+
}

0 commit comments

Comments
 (0)