${escapeHtml(deck.title)}
${deck.description ? `${escapeHtml(deck.description)}
` : ''} ${tags ? `` : ''}import 'dotenv/config'
import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { checkProject, printIssues } from './check.ts'
import type { EasySlidesConfig } from './lib/config.ts'
import type { DeckMetadata } from './lib/content.ts'
import { joinBase, normalizeSiteBase } from './lib/site-base.ts'
import { auditBuiltDecks } from './lib/overflow-audit.ts'
import { formatOverflowAuditResult } from './lib/overflow-report.ts'
import { runSlidev } from './lib/run-slidev.ts'
import { resolveTheme } from './lib/theme.ts'
const cwd = process.cwd()
const siteBase = normalizeSiteBase(process.env.SITE_BASE)
let config: EasySlidesConfig
let dist: string
async function main() {
const result = await checkProject(cwd)
config = result.config
dist = path.join(cwd, config.outDir)
const { decks, issues } = result
printIssues(issues, cwd)
if (issues.some(issue => issue.level === 'error'))
throw new Error('内容检查失败,已停止构建')
const published = decks.filter(deck => !deck.draft)
await rm(dist, { recursive: true, force: true })
await mkdir(dist, { recursive: true })
for (const deck of published)
await buildDeck(deck)
await reportSlideOverflow(published)
await writeFile(path.join(dist, 'index.html'), renderIndex(published), 'utf8')
await writeFile(path.join(dist, '_headers'), renderHeaders(), 'utf8')
await writeFile(path.join(dist, '_redirects'), renderRedirects(published), 'utf8')
console.log(`\n构建完成:${published.length} 套演示 → ${path.relative(cwd, dist)}`)
}
async function buildDeck(deck: DeckMetadata) {
const output = path.join(dist, deck.slug)
const base = joinBase(siteBase, deck.slug)
console.log(`\nBuilding ${deck.slug} (${base})`)
await runSlidev([
'build',
deck.entry,
'--theme',
resolveTheme(config.theme),
'--out',
output,
'--base',
base,
'--router-mode',
'hash',
])
const assets = path.join(deck.directory, 'assets')
await cp(assets, path.join(output, 'assets'), { recursive: true, force: true }).catch(() => undefined)
await copySpaEntry(output, 'presenter')
await copySpaEntry(output, 'overview')
await copySpaEntry(output, 'notes-edit')
}
async function copySpaEntry(output: string, route: string) {
const html = await readFile(path.join(output, 'index.html'), 'utf8')
const routeBootstrap = ``
const routedHtml = html.replace('', `${routeBootstrap}`)
const directory = path.join(output, route)
await mkdir(directory, { recursive: true })
await writeFile(path.join(directory, 'index.html'), routedHtml, 'utf8')
}
async function reportSlideOverflow(decks: DeckMetadata[]) {
if (!decks.length)
return
console.log('\n检查编译后的幻灯片内容边界...')
const result = await auditBuiltDecks({ root: dist, decks, siteBase })
formatOverflowAuditResult(result, cwd).forEach(line => console.log(line))
}
function renderIndex(decks: DeckMetadata[]) {
const cards = decks.map((deck) => {
const href = joinBase(siteBase, deck.slug)
const cover = deck.cover
? ``
: `
${escapeHtml(deck.description)}
` : ''} ${tags ? `` : ''}MARKDOWN PRESENTATIONS
${escapeHtml(config.description)}
暂无公开演示。
'}