- Introduced a new script `prepare-hero-variants.mjs` to generate responsive hero image variants in WebP format. - Added a fallback image `hero_fallback.png` for each variant. - Created an API endpoint `hero-images.get.js` to retrieve available hero image variants and their fallback images. - Implemented directory and file checks to ensure the existence of required images before serving.
88 lines
2.2 KiB
JavaScript
88 lines
2.2 KiB
JavaScript
import { promises as fs } from 'fs'
|
|
import path from 'path'
|
|
|
|
const HERO_ROOT_CANDIDATES = [
|
|
path.join(process.cwd(), 'public', 'images', 'hero'),
|
|
path.join(process.cwd(), '.output', 'public', 'images', 'hero'),
|
|
path.join(process.cwd(), '..', 'public', 'images', 'hero'),
|
|
path.join(process.cwd(), '..', '.output', 'public', 'images', 'hero')
|
|
]
|
|
|
|
const FALLBACK_FILE_CANDIDATES = [
|
|
'hero_fallback.webp',
|
|
'hero_fallback.jpg',
|
|
'hero_fallback.jpeg',
|
|
'hero_fallback.png'
|
|
]
|
|
|
|
async function findExistingDir(paths) {
|
|
for (const candidate of paths) {
|
|
try {
|
|
const stats = await fs.stat(candidate)
|
|
if (stats.isDirectory()) return candidate
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
async function fileExists(filePath) {
|
|
try {
|
|
const stats = await fs.stat(filePath)
|
|
return stats.isFile()
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
async function listHeroVariants(heroRoot) {
|
|
const dirEntries = await fs.readdir(heroRoot, { withFileTypes: true })
|
|
const variants = []
|
|
|
|
for (const entry of dirEntries) {
|
|
if (!entry.isDirectory()) continue
|
|
|
|
const key = entry.name
|
|
const variantDir = path.join(heroRoot, key)
|
|
const mobileFile = 'hero_960.webp'
|
|
const desktopFile = 'hero_1600.webp'
|
|
|
|
const mobilePath = path.join(variantDir, mobileFile)
|
|
const desktopPath = path.join(variantDir, desktopFile)
|
|
|
|
if (!(await fileExists(mobilePath)) || !(await fileExists(desktopPath))) {
|
|
continue
|
|
}
|
|
|
|
let fallbackFile = desktopFile
|
|
for (const candidate of FALLBACK_FILE_CANDIDATES) {
|
|
if (await fileExists(path.join(variantDir, candidate))) {
|
|
fallbackFile = candidate
|
|
break
|
|
}
|
|
}
|
|
|
|
variants.push({
|
|
key,
|
|
mobileWebp: `/images/hero/${key}/${mobileFile}`,
|
|
desktopWebp: `/images/hero/${key}/${desktopFile}`,
|
|
fallback: `/images/hero/${key}/${fallbackFile}`
|
|
})
|
|
}
|
|
|
|
return variants.sort((a, b) => a.key.localeCompare(b.key, 'de'))
|
|
}
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const heroRoot = await findExistingDir(HERO_ROOT_CANDIDATES)
|
|
if (!heroRoot) {
|
|
return { variants: [] }
|
|
}
|
|
|
|
const variants = await listHeroVariants(heroRoot)
|
|
setHeader(event, 'Cache-Control', 'public, max-age=300, stale-while-revalidate=600')
|
|
|
|
return { variants }
|
|
})
|