Auto-detect content icon collections for the server bundle instead of hand-maintaining the list
This commit is contained in:
+52
-1
@@ -1,9 +1,56 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import { execFileSync } from 'node:child_process'
|
import { execFileSync } from 'node:child_process'
|
||||||
|
import { readdirSync, readFileSync } from 'node:fs'
|
||||||
|
import { join } from 'node:path'
|
||||||
import { createResolver } from '@nuxt/kit'
|
import { createResolver } from '@nuxt/kit'
|
||||||
|
|
||||||
const { resolve } = createResolver(import.meta.url)
|
const { resolve } = createResolver(import.meta.url)
|
||||||
|
|
||||||
|
// Every `i-<collection>-<name>` icon referenced from content/*.md needs its
|
||||||
|
// collection listed below, but Nuxt Icon's own static scanner only looks at
|
||||||
|
// .vue/.ts source, not markdown content, so it can't find these on its own.
|
||||||
|
// Scanning content here instead of hand-maintaining the list means a new
|
||||||
|
// icon collection used in an article gets bundled automatically on the next
|
||||||
|
// build; the only manual step left is `npm install @iconify-json/<name>`
|
||||||
|
// for a genuinely new collection, and a missing one now fails the build
|
||||||
|
// loudly (unresolved import) instead of silently breaking at runtime behind
|
||||||
|
// the CSP (icons falling back to a live, blocked api.iconify.design call).
|
||||||
|
function scanContentIconCollections(): string[] {
|
||||||
|
// Collection prefixes can contain hyphens themselves (simple-icons,
|
||||||
|
// fluent-color), same as the separator before the icon name, so a plain
|
||||||
|
// "first segment" split is ambiguous. Matching against the actual
|
||||||
|
// installed @iconify-json package names, longest first, resolves it.
|
||||||
|
const installed = readdirSync(resolve('./node_modules/@iconify-json'))
|
||||||
|
.sort((a, b) => b.length - a.length)
|
||||||
|
const found = new Set<string>()
|
||||||
|
const pattern = /icon=["']i-([a-z0-9-]+)["']|icon:\s*["']?i-([a-z0-9-]+)/g
|
||||||
|
function walk(dir: string) {
|
||||||
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
||||||
|
const full = join(dir, entry.name)
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
walk(full)
|
||||||
|
}
|
||||||
|
else if (entry.name.endsWith('.md')) {
|
||||||
|
const text = readFileSync(full, 'utf8')
|
||||||
|
for (const match of text.matchAll(pattern)) {
|
||||||
|
const iconRef = match[1] ?? match[2]
|
||||||
|
const collection = installed.find(name => iconRef === name || iconRef.startsWith(`${name}-`))
|
||||||
|
// Falls back to the first segment for a collection that isn't
|
||||||
|
// installed yet: still wrong, but it now surfaces as a clear
|
||||||
|
// "cannot resolve @iconify-json/<name>" build error to fix,
|
||||||
|
// rather than a silent runtime CSP block.
|
||||||
|
found.add(collection ?? iconRef.split('-')[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walk(resolve('./content'))
|
||||||
|
// 'brand' is the local customCollections prefix (app/assets/brand-icons),
|
||||||
|
// not an installable Iconify package.
|
||||||
|
found.delete('brand')
|
||||||
|
return [...found]
|
||||||
|
}
|
||||||
|
|
||||||
// Contributors per page: read straight from git history rather than an
|
// Contributors per page: read straight from git history rather than an
|
||||||
// API, so it needs no token and no network call, but the CI checkout must
|
// API, so it needs no token and no network call, but the CI checkout must
|
||||||
// fetch full history (not a shallow clone) or every file will only show
|
// fetch full history (not a shallow clone) or every file will only show
|
||||||
@@ -84,8 +131,12 @@ export default defineNuxtConfig({
|
|||||||
// bundle. Without this, they fall back to a live api.iconify.design
|
// bundle. Without this, they fall back to a live api.iconify.design
|
||||||
// request at prerender time, which times out wherever outbound access
|
// request at prerender time, which times out wherever outbound access
|
||||||
// is restricted. Bundling all three collections in full avoids that.
|
// is restricted. Bundling all three collections in full avoids that.
|
||||||
|
// Everything else used as a literal icon in content/*.md is added by
|
||||||
|
// scanContentIconCollections() above, so a new collection introduced in
|
||||||
|
// an article gets bundled automatically instead of needing a manual
|
||||||
|
// addition here.
|
||||||
serverBundle: {
|
serverBundle: {
|
||||||
collections: ['simple-icons', 'lucide', 'vscode-icons'],
|
collections: [...new Set(['simple-icons', 'lucide', 'vscode-icons', ...scanContentIconCollections()])],
|
||||||
},
|
},
|
||||||
// The fixed, small set of codeIcon values above. Forces them into the
|
// The fixed, small set of codeIcon values above. Forces them into the
|
||||||
// content-hashed client bundle instead of Nuxt Icon's runtime
|
// content-hashed client bundle instead of Nuxt Icon's runtime
|
||||||
|
|||||||
Generated
+70
@@ -6,6 +6,13 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "docudjeex",
|
"name": "docudjeex",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@iconify-json/carbon": "^1.2.26",
|
||||||
|
"@iconify-json/cbi": "^1.2.59",
|
||||||
|
"@iconify-json/cib": "^1.2.3",
|
||||||
|
"@iconify-json/fluent-color": "^1.2.21",
|
||||||
|
"@iconify-json/logos": "^1.2.14",
|
||||||
|
"@iconify-json/noto": "^1.2.7",
|
||||||
|
"@iconify-json/solar": "^1.2.10",
|
||||||
"@nuxtjs/i18n": "^10.6.0",
|
"@nuxtjs/i18n": "^10.6.0",
|
||||||
"better-sqlite3": "^12.11.1",
|
"better-sqlite3": "^12.11.1",
|
||||||
"docus": "^5.13.0",
|
"docus": "^5.13.0",
|
||||||
@@ -1355,6 +1362,51 @@
|
|||||||
"url": "https://github.com/sponsors/nzakas"
|
"url": "https://github.com/sponsors/nzakas"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@iconify-json/carbon": {
|
||||||
|
"version": "1.2.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/carbon/-/carbon-1.2.26.tgz",
|
||||||
|
"integrity": "sha512-UVzlnCAzSkrNydW3GYESeggndriR1JSgU5M8DNz9S0Fu10I3NpJUYPWar+WYjMAQUIm9B7mljPpc30oal3PRSQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@iconify-json/cbi": {
|
||||||
|
"version": "1.2.59",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/cbi/-/cbi-1.2.59.tgz",
|
||||||
|
"integrity": "sha512-kvp05ix+eJk509JJ8CTEUvdNx0F5x9Xg5oBMMDnjyLzKYZTh7nEWswvGKPmAmnEQ0pVjt8R+eS65LwYmi1OvFA==",
|
||||||
|
"license": "CC-BY-NC-SA-4.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@iconify-json/cib": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/cib/-/cib-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-MMvRXVTHt82z3bYN19JDAjv/X8OBNC/1B3I334SV/1nyhdPeeyvJZVoI1cGuNqYznBjMnWxKPtIhhiVgGQ1CzQ==",
|
||||||
|
"license": "CC0-1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@iconify-json/fluent-color": {
|
||||||
|
"version": "1.2.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/fluent-color/-/fluent-color-1.2.21.tgz",
|
||||||
|
"integrity": "sha512-VETjGx7BMpVsCR3HV5g5t6oBGZ92XKzIRClS5xUvDn1YHAkQTF9OyF/aFdtxYOC8JROoI1SNO/Ql6jZeK7mroA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@iconify-json/logos": {
|
||||||
|
"version": "1.2.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/logos/-/logos-1.2.14.tgz",
|
||||||
|
"integrity": "sha512-O36DicXkgAMT6NAsH7MTWlOql8NktHz9fBCItTjz6L/9gyRXw4vQj6qTeVgww5UZWiVugUV1MhVFA/g9HWIkBw==",
|
||||||
|
"license": "CC0-1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@iconify-json/lucide": {
|
"node_modules/@iconify-json/lucide": {
|
||||||
"version": "1.2.127",
|
"version": "1.2.127",
|
||||||
"resolved": "https://registry.npmjs.org/@iconify-json/lucide/-/lucide-1.2.127.tgz",
|
"resolved": "https://registry.npmjs.org/@iconify-json/lucide/-/lucide-1.2.127.tgz",
|
||||||
@@ -1364,6 +1416,15 @@
|
|||||||
"@iconify/types": "*"
|
"@iconify/types": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@iconify-json/noto": {
|
||||||
|
"version": "1.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/noto/-/noto-1.2.7.tgz",
|
||||||
|
"integrity": "sha512-2pNHliXnMLpnepNTZwR9hPBSl6GmhIfXPnudFCHY5v9pJhmA7LoVb/pFY0qLDY/k+3ikET8RXRf7XFxc/pHObA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@iconify-json/simple-icons": {
|
"node_modules/@iconify-json/simple-icons": {
|
||||||
"version": "1.2.94",
|
"version": "1.2.94",
|
||||||
"resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.94.tgz",
|
"resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.94.tgz",
|
||||||
@@ -1373,6 +1434,15 @@
|
|||||||
"@iconify/types": "*"
|
"@iconify/types": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@iconify-json/solar": {
|
||||||
|
"version": "1.2.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify-json/solar/-/solar-1.2.10.tgz",
|
||||||
|
"integrity": "sha512-ChpZ3kNw8nDhHfUoLq5JJ3AdIzytFm57dFkjAS0fjXnL5a7WwibTINjMKfvqQDhuXBrgqejNLyGp8CCpG8UyCg==",
|
||||||
|
"license": "CC-BY-4.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@iconify-json/vscode-icons": {
|
"node_modules/@iconify-json/vscode-icons": {
|
||||||
"version": "1.2.76",
|
"version": "1.2.76",
|
||||||
"resolved": "https://registry.npmjs.org/@iconify-json/vscode-icons/-/vscode-icons-1.2.76.tgz",
|
"resolved": "https://registry.npmjs.org/@iconify-json/vscode-icons/-/vscode-icons-1.2.76.tgz",
|
||||||
|
|||||||
@@ -6,6 +6,13 @@
|
|||||||
"build": "NUXT_SITE_URL=https://docu.djeex.fr nuxt build"
|
"build": "NUXT_SITE_URL=https://docu.djeex.fr nuxt build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@iconify-json/carbon": "^1.2.26",
|
||||||
|
"@iconify-json/cbi": "^1.2.59",
|
||||||
|
"@iconify-json/cib": "^1.2.3",
|
||||||
|
"@iconify-json/fluent-color": "^1.2.21",
|
||||||
|
"@iconify-json/logos": "^1.2.14",
|
||||||
|
"@iconify-json/noto": "^1.2.7",
|
||||||
|
"@iconify-json/solar": "^1.2.10",
|
||||||
"@nuxtjs/i18n": "^10.6.0",
|
"@nuxtjs/i18n": "^10.6.0",
|
||||||
"better-sqlite3": "^12.11.1",
|
"better-sqlite3": "^12.11.1",
|
||||||
"docus": "^5.13.0",
|
"docus": "^5.13.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user