fix: inject default labels to support custom code block icons at correct timing, close #578

This commit is contained in:
JasonXuDeveloper - 傑 2025-07-15 12:44:36 +10:00
parent c124dd7dc1
commit 7e4632f1b8
3 changed files with 98 additions and 24 deletions

View File

@ -31,11 +31,7 @@ export function titleCollectorPlugin(md: MarkdownIt) {
// Extract title from token.info before it gets modified by other plugins
const title = extractTitle(token.info)
// Only collect actual titles (not language fallbacks)
if (title && title !== extractTitle('')) {
globalTitleCollector.add(title)
}
globalTitleCollector.add(title)
// Call the original fence renderer
return fence(...args)

View File

@ -58,9 +58,9 @@ export async function setupMarkdownPlugins(
// custom plugins
md.use(highlightLinePlugin)
.use(titleCollectorPlugin)
.use(preWrapperPlugin, { theme, siteConfig })
.use(snippetPlugin, options?.userRoot)
.use(titleCollectorPlugin)
.use(containerPlugin, {
languages: siteConfig.languages,
...mdOptions?.container,

View File

@ -1,4 +1,4 @@
import type { PluginOption } from 'vite'
import type { PluginOption, ViteDevServer } from 'vite'
import type { ValaxyServerOptions } from '../options'
import type { ValaxyNode } from '../types'
@ -155,9 +155,6 @@ export async function ViteValaxyPlugins(
}
}
// Get code block titles collected during markdown processing (no file I/O needed)
const codeBlockTitles = getGlobalTitleCollector()
const builtinCustomIcon = {
nodejs: 'vscode-icons:file-type-node',
playwright: 'vscode-icons:file-type-playwright',
@ -165,19 +162,100 @@ export async function ViteValaxyPlugins(
eslint: 'vscode-icons:file-type-eslint',
}
plugins.push(
groupIconVitePlugin({
customIcon: {
...builtinCustomIcon,
...valaxyConfig.groupIcons?.customIcon,
},
defaultLabels: [
...valaxyConfig.groupIcons?.defaultLabels || [],
...Object.keys(builtinCustomIcon),
...Object.keys(valaxyConfig.groupIcons?.customIcon || {}),
...Array.from(codeBlockTitles),
],
}),
)
let cachedGroupIconsCSS: string | null = null
// Create a custom plugin that intercepts the virtual CSS generation
const dynamicGroupIconPlugin: PluginOption = {
name: 'vitepress-plugin-group-icons',
enforce: 'post' as const,
configureServer(server: ViteDevServer) {
// Watch for markdown file changes to invalidate the virtual module
const markdownGlobs = roots.map(root => `${root}/**/*.md`)
server.watcher.add(markdownGlobs)
server.watcher.on('change', (file: string) => {
if (file.endsWith('.md')) {
// Clear cache and invalidate the virtual module when markdown files change
cachedGroupIconsCSS = null
const module = server.moduleGraph.getModuleById('\0virtual:group-icons.css')
if (module) {
server.reloadModule(module)
}
}
})
},
resolveId(id: string) {
if (id === 'virtual:group-icons.css') {
return '\0virtual:group-icons.css'
}
return undefined
},
async load(id: string) {
if (id === '\0virtual:group-icons.css') {
// Return cached CSS if available (for build mode after generateBundle)
if (cachedGroupIconsCSS !== null) {
return cachedGroupIconsCSS
}
// For dev mode or initial build, generate with current titles
const codeBlockTitles = getGlobalTitleCollector()
// Create the original plugin with dynamic titles
const originalPlugin = groupIconVitePlugin({
customIcon: {
...builtinCustomIcon,
...valaxyConfig.groupIcons?.customIcon,
},
defaultLabels: [
...valaxyConfig.groupIcons?.defaultLabels || [],
...Object.keys(builtinCustomIcon),
...Object.keys(valaxyConfig.groupIcons?.customIcon || {}),
...Array.from(codeBlockTitles),
],
})
// Call the original plugin's load method
if (originalPlugin && typeof originalPlugin === 'object' && 'load' in originalPlugin) {
const css = (originalPlugin as any).load(id)
return css
}
return ''
}
return undefined
},
// In build mode, regenerate the CSS after all markdown files have been processed
generateBundle() {
if (this.meta.rollupVersion) { // Build mode only
// At this point, all markdown files should have been processed
const codeBlockTitles = getGlobalTitleCollector()
// Generate the final CSS with all collected titles
const originalPlugin = groupIconVitePlugin({
customIcon: {
...builtinCustomIcon,
...valaxyConfig.groupIcons?.customIcon,
},
defaultLabels: [
...valaxyConfig.groupIcons?.defaultLabels || [],
...Object.keys(builtinCustomIcon),
...Object.keys(valaxyConfig.groupIcons?.customIcon || {}),
...Array.from(codeBlockTitles),
],
})
// Cache the final CSS
if (originalPlugin && typeof originalPlugin === 'object' && 'load' in originalPlugin) {
cachedGroupIconsCSS = (originalPlugin as any).load('\0virtual:group-icons.css')
}
}
},
}
plugins.push(dynamicGroupIconPlugin)
return plugins
}