import { promises as fs } from 'fs' import path from 'path' import { ImgHTMLAttributes } from 'react' import sharp from 'sharp' const outputDir = path.join(process.cwd(), '.next/static/images') const serverPath = '/_next/static/images/' interface ReqProps { src: string, alt: string, } type FixedSingleDimension = {width: number} | {height: number} type FixedBothDimension = {width: number, height: number} type MultiSize = {width: number[]} | {height: number[]} type SizeProps = FixedSingleDimension | FixedBothDimension | MultiSize type ImageAttrs = Omit, "width" | "height" | "src"> type ImageProps = ImageAttrs & SizeProps & ReqProps interface ProcessedImage { hostPath: string, randPrefix: string, widths: {[width: number] : string} } async function ImageServer({src,...imgAttrs}: ImageProps) { const srcImg = sharp(src) const extension = path.extname(src) const filename = path.basename(src, extension) const randPrefix = (Math.random() + 1).toString(36).substring(7) const width = 'width' in imgAttrs ? imgAttrs.width : null const height = 'height' in imgAttrs ? imgAttrs.height : null console.log(`processing ${src} for width ${width} and height ${height}`) // Make sure we can write to the dir await fs.mkdir(outputDir, {recursive: true}) // Handle where we have an array of dimensions if (Array.isArray(width) || Array.isArray(height)) { const dimension = Array.isArray(width) ? 'width' : 'height' const sizes = Array.isArray(width) ? width : height as number[] const suffix = dimension.charAt(0) // Copy in original fs.copyFile(src, path.join(outputDir, `${randPrefix}-${filename}${extension}`)) // Create resized copies const srcSetLines = await Promise.all(sizes .map(async size => { const outputName = `${randPrefix}-${filename}-${size}${suffix}${extension}` const outputPath = path.join(outputDir, outputName) return srcImg .resize({[dimension]: size}) .toFile(outputPath) .then(result => `${serverPath}${outputName} ${result.width}w`) })) return ( ) } else { const dimensions = { width: typeof width === 'number' ? width : undefined, height: typeof height === 'number' ? height : undefined } const dimensionString = (() => { if (dimensions.height && dimensions.height) return `${dimensions.width}x${dimensions.height}` if (dimensions.width) return `${dimensions.width}w` return `${dimensions.height}h` })() const outputName = `${randPrefix}-${filename}-${dimensionString}${extension}` const outputPath = path.join(outputDir, outputName) const outputSrc = serverPath + outputName await srcImg.resize(dimensions).toFile(outputPath) return ( ) } } export default function ImageServerWrap(props: ImageProps) { return ( <> {/* @ts-expect-error Async Server Component */} ) }