import type { App } from 'vuepress' import type { ThemeHomeConfig } from '../../shared/index.js' import { isEmptyObject, uniq } from '@pengzhanbo/utils' import { isPackageExists } from 'local-pkg' import { getUserAgent, resolveCommand } from 'package-manager-detector' import { colors } from 'vuepress/utils' import { createTranslate, logger, perf, writeTemp } from '../utils/index.js' const effectDeps: Record = { 'prism': ['ogl'], 'pixel-blast': ['three', 'postprocessing'], 'hyper-speed': ['three', 'postprocessing'], 'liquid-ether': ['three'], 'dot-grid': ['gsap'], 'iridescence': ['ogl'], 'orb': ['ogl'], 'beams': ['three'], 'dark-veil': ['ogl'], } const effectMapping: Record = { 'tint-plate': 'TintPlate', 'prism': 'Prism', 'pixel-blast': 'PixelBlast', 'hyper-speed': 'HyperSpeed', 'liquid-ether': 'LiquidEther', 'dot-grid': 'DotGrid', 'iridescence': 'Iridescence', 'orb': 'Orb', 'beams': 'Beams', 'lightning': 'Lightning', 'dark-veil': 'DarkVeil', } const allEffects = Object.keys(effectMapping) const t = createTranslate({ en: { unknown: `[Home hero background effect] Unknown effect: {{ effect }}`, uninstall: `[Home hero background effect] The following effect is missing necessary dependencies: {{ deps }}`, install: `Run the installation command: {{ command }}`, }, zh: { unknown: `[首页 hero 背景效果] 未知的 effect: {{ effect }}`, uninstall: `[首页 hero 背景效果] 以下效果缺少必要依赖: {{ deps }}`, install: `运行安装命令: {{ command }}`, }, }) export async function prepareHomeHeroEffects(app: App): Promise { perf.mark('prepare:home-hero-effects') const { effects, unknownEffects } = getEffectsByFrontmatter(app) if (unknownEffects.length) logger.warn(t('unknown', { effect: colors.cyan(unknownEffects.join(', ')) })) await writeToInternalTemp(app, effects) detectMissingDeps(effects) perf.log('prepare:home-hero-effects') } async function writeToInternalTemp(app: App, effects: string[]) { let imports: string = '' let exports: string = 'export const effectComponents = {\n' for (const effect of effects) { const component = effectMapping[effect] imports += `import ${component} from '@theme/background/${component}.vue'\n` exports += ` '${effect}': ${component},\n` } exports += '}\n\nexport const effects = Object.keys(effectComponents)\n' const content = `${imports}\n${exports}` await writeTemp(app, 'internal/home-hero-effects.js', content) } function getEffectsByFrontmatter(app: App) { const effects: string[] = [] const unknownEffects: string[] = [] for (const page of app.pages) { const fm = page.frontmatter const config = fm.config as ThemeHomeConfig[] if (!(fm.home || fm.pageLayout === 'home') || config?.length === 0) continue for (const item of config) { if (item.type === 'hero') { const effect = item.effect if (effect) { if (allEffects.includes(effect)) { effects.push(effect) } else { unknownEffects.push(effect) } } // compatibility if (item.background) { if (allEffects.includes(item.background)) effects.push(item.background) } } } } return { effects: uniq(effects), unknownEffects: uniq(unknownEffects) } } function detectMissingDeps(effects: string[]) { const missingDeps: Record = {} for (const effect of effects) { const deps = effectDeps[effect] if (deps?.length) { const uninstall = deps.filter(dep => !isPackageExists(dep)) if (uninstall.length) missingDeps[effect] = uninstall } } if (isEmptyObject(missingDeps)) return const dependencies = uniq(Object.values(missingDeps).flat()) logger.warn(t('uninstall', { deps: colors.bold(JSON.stringify(missingDeps)) })) const agent = getUserAgent() if (agent) { const { command = '', args = [] } = resolveCommand(agent, 'add', dependencies) || {} logger.info(t('install', { command: colors.cyan(`${command} ${args.join(' ')}`) })) } }