vuepress-theme-plume/theme/src/node/prepare/prepareHomeHeroEffects.ts

132 lines
4.1 KiB
TypeScript

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<string, string[]> = {
'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<string, string> = {
'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<void> {
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<string, string[]> = {}
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(' ')}`) }))
}
}