fix: revert Next.js Image component for Cloudflare Workers compatibility

🐛 Bug Fix:

The Next.js <Image> component requires Node.js APIs that aren't available
in Cloudflare Workers runtime, causing 'Image constructor: new is required' errors.

Changes:
- Revert hero-section.tsx to use background-image CSS
- Revert artists-section.tsx to use native <img> tags
- Add loading='lazy' attributes for native lazy loading
- Keep images.unoptimized: true in next.config.mjs
- Add clear comment explaining Cloudflare compatibility requirement

 What's Still Working:
- All SEO improvements (metadata, Open Graph, Twitter Cards)
- JSON-LD structured data (LocalBusiness, Organization)
- Canonical URLs on all pages
- Font preloading
- Page-specific metadata

Note: Native <img> tags with loading='lazy' provide basic optimization
without requiring Next.js Image APIs. For Cloudflare R2 image optimization,
consider using Cloudflare Images service separately.

Issue: #GH-419 (React error)
Platform: Cloudflare Workers
This commit is contained in:
Nicholai 2025-10-08 19:13:10 -06:00
parent f9a8464b1d
commit 1be512f658
3 changed files with 15 additions and 36 deletions

View File

@ -108,24 +108,20 @@ export function ArtistsSection() {
<div className={`relative w-full ${aspectFor(i)} overflow-hidden rounded-md border border-white/10 bg-black`}>
{/* Imagery */}
<div className="absolute inset-0 artist-image">
<Image
<img
src={artist.workImages?.[0] || "/placeholder.svg"}
alt={`${artist.name} tattoo work`}
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
className="object-cover"
className="w-full h-full object-cover"
loading="lazy"
/>
<div className="absolute inset-0 bg-black/30 z-10"></div>
<div className="absolute inset-0 bg-black/30"></div>
{/* Portrait with feathered mask */}
<div className="absolute left-0 top-0 w-3/5 h-full pointer-events-none z-20">
<Image
<div className="absolute left-0 top-0 w-3/5 h-full pointer-events-none">
<img
src={artist.faceImage || "/placeholder.svg"}
alt={`${artist.name} portrait`}
fill
sizes="(max-width: 640px) 60vw, (max-width: 1024px) 30vw, 20vw"
className="object-cover"
className="w-full h-full object-cover"
style={{
maskImage: "linear-gradient(to right, black 0%, black 70%, transparent 100%)",
WebkitMaskImage: "linear-gradient(to right, black 0%, black 70%, transparent 100%)",

View File

@ -1,7 +1,6 @@
"use client"
import { useEffect, useState } from "react"
import Image from "next/image"
import { useFeatureFlag } from "@/components/feature-flags-provider"
import { Button } from "@/components/ui/button"
@ -30,20 +29,13 @@ export function HeroSection() {
{/* Background Layer - Slowest parallax */}
<div
ref={parallax.background.ref}
className="absolute inset-0 will-change-transform"
style={parallax.background.style}
className="absolute inset-0 bg-cover bg-center bg-no-repeat will-change-transform"
style={{
backgroundImage: "url(/united-logo-full.jpg)",
...parallax.background.style,
}}
aria-hidden="true"
>
<Image
src="/united-logo-full.jpg"
alt=""
fill
priority
quality={90}
sizes="100vw"
className="object-cover object-center"
/>
</div>
{/* Midground Layer - Overlay with subtle parallax */}
<div

View File

@ -7,18 +7,9 @@ const nextConfig = {
ignoreBuildErrors: true,
},
images: {
unoptimized: false,
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
minimumCacheTTL: 60,
domains: [],
remotePatterns: [
{
protocol: 'https',
hostname: '**',
},
],
// Must be unoptimized for Cloudflare Workers compatibility
// Next.js Image component requires Node.js APIs not available in Workers runtime
unoptimized: true,
},
output: "standalone",
}