I finished a customer website (look at dev2.bodyharmoniewien.at) and in the treatment sections, there’s an image reel which receives the images by an array of image paths, set in a content.tsx file for each treatment.
If I run the website in development mode at localhost:3000, I can see all images.
But when I deployed the website via Docker on our production server, strangely some images are being shown, but some are not – even though they have the same paths.
All images of “HotStone” are loading (but with a suspicious delay), so does the logo-image, the hand-with-flower-image and the sample images of “Studio Niederösterreich”.
The docker-container logs show this here:
▲ Next.js 14.2.3
- Local:
- Network:
✓ Starting...
✓ Ready in 186ms
⨯ The requested resource isn't a valid image for /static/images/BodyClassic3.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/BodyClassic4.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/BodyClassic5.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/BodyClassic2.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/BodyClassic1.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/StudioWien4.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/StudioWien2.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/StudioWien3.jpg received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /static/images/StudioWien7.jpg received text/html; charset=utf-8
and so on.....
The browser console shows these errors:
Browser console errors
Here is my project directory schema:
components/
├── atoms/
│ ├── BookNowButton.tsx
│ ├── FlyingButterflyMouse.tsx
│ ├── ImageCollection.tsx
│ ├── ImageReel.tsx
│ ├── Logo.tsx
│ ├── LottieAnimation.tsx
│ ├── MarqueeElement.tsx
│ ├── MobileSnackbar.tsx
│ ├── MouseCursor.tsx
│ └── ProductListElement.tsx
├── layout/
│ ├── Credits.tsx
│ ├── DefaultSpacing.tsx
│ └── LegalMenu.tsx
├── sections/
│ ├── StudioSection.tsx
│ ├── TreatmentSectionDesktop.tsx
│ └── TreatmentSectionMobile.tsx
├── templates/
│ ├── TwoByTwo.tsx
│ └── SectionIndicator.tsx
lib/
├── config/
├── content/
│ ├── content.tsx
│ ├── helper/
│ └── models/
node_modules/
pages/
├── datenschutz/
├── impressum/
├── _app.tsx
├── _document.tsx
├── 404.tsx
└── index.tsx
public/
├── static/
│ ├── animation/
│ ├── fonts/
│ └── images/
│ ├── BodyClassic1.jpg
│ ├── BodyClassic2.jpg
│ ├── BodyClassic3.jpg
│ ├── BodyClassic4.jpg
│ ├── BodyClassic5.jpg
│ ├── BodyClassic6.jpg
│ ├── BodyHarmonieWienLogoFinal.png
│ ├── BodyHotStone1.jpg
│ ├── BodyHotStone2.jpg
│ ├── BodyHotStone3.jpg
│ ├── BodyHotStone4.jpg
│ ├── BodyHotStone5.jpg
│ ├── BodyHotStone6.jpg
│ ├── BodyHotStone7.jpg
│ ├── BodyKlang1.jpg
│ ├── BodyKlang2.jpg
│ ├── BodyKlang3.jpg
│ ├── BodyKlang4.jpg
│ ├── BodyKlang5.jpg
│ ├── BodyKlang6.jpg
│ ├── BodyTantra1.jpg
│ ├── BodyTantra2.jpg
│ ├── BodyTantra3.jpg
│ ├── BodyTantra4.jpg
│ ├── BodyTantra5.jpg
│ ├── BodyTantra6.jpg
│ ├── christian.jpg
│ ├── flowers_vertical.jpg
│ ├── StudioWien1.jpg
│ ├── StudioWien2.jpg
│ ├── StudioWien3.jpg
│ ├── StudioWien4.jpg
│ ├── StudioWien5.jpg
│ ├── StudioWien6.jpg
│ ├── StudioWien7.jpg
│ ├── StudioWien8.jpg
│ ├── sven.png
│ ├── tantracropped.jpg
│ ├── tantracropped1.jpg
│ └── white_flower.png
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── apple-touch-icon.png
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── mstile-150x150.png
├── robots.txt
├── safari-pinned-tab.svg
└── site.webmanifest
styles/
.dockerignore
.eslintrc.json
.gitattributes
.gitignore
.npmrc
Dockerfile
next-env.d.ts
next.config.js
package.json
pnpm-lock.yaml
postcss.config.js
README.md
tailwind.config.js
tsconfig.json
Here is the website content (content.tsx):
import {Addon, Treatment} from "@/lib/models/treatment.model";
const addonDetails: { [key: string]: Addon } = {
Meridianstift: {text: 'Meridianstift'},
Schröpfgläser: {text: 'Schröpfgläser'},
BodyGun: {text: 'Body-Gun'},
Infrarotlampe: {text: 'Infrarotlampe'},
BioAromaöl: {
text: 'Bio-Aromaöle',
description: 'Wir führen ein breites Sortiment an verschiedensten Aromaölen. Frag uns vor Deiner Anwendung.'
},
HotBodyWachs: {
text: 'Hot-Body-Wachs',
description: 'Speziell erwärmtes Wachs (verschiedene Duftvarianten) wird zu Deiner Anwendung verwendet. Es bietet einen besonderen cremigen Body Feeling für Deine Haut.'
}
};
const getAddons = (keys: string[]): Addon[] => keys.map(key => addonDetails[key]);
export const treatments: Treatment[] = [
{
id: '1',
title: 'Body Classic',
images: [
'/static/images/BodyClassic1.jpg',
'/static/images/BodyClassic2.jpg',
'/static/images/BodyClassic3.jpg',
'/static/images/BodyClassic4.jpg',
'/static/images/BodyClassic5.jpg'
],
minuteOptions: [
],
addons: getAddons([
'Meridianstift',
'Schröpfgläser',
'BodyGun',
'Infrarotlampe',
'BioAromaöl',
'HotBodyWachs'
]),
description: 'Unsere langjährige Fachkompetenz erkennt Deine Problematik und hilft durch gezielte Berührungen Blockaden zu lösen, und Dich wieder ins energetische Gleichgewicht zu führen. Der Wohlfühlfaktor steht im Gleichklang mit Deiner Behandlung. <br/><br/>Anwendung je nach gebuchter Dauer, auf Rücken, Beine, Füße, Bauch und Kopf mit Gesicht.'
},
{
id: '2',
title: 'HotStone',
images: [
'/static/images/BodyHotStone1.jpg',
'/static/images/BodyHotStone2.jpg',
'/static/images/BodyHotStone3.jpg',
'/static/images/BodyHotStone4.jpg',
'/static/images/BodyHotStone5.jpg',
'/static/images/BodyHotStone6.jpg',
'/static/images/BodyHotStone7.jpg'
],
minuteOptions: [
],
addons: getAddons(['Infrarotlampe', 'BioAromaöl', 'HotBodyWachs']),
description: 'Ursprung aus dem asiatisch, pazifischen Raum. Bei der Body Hot Stone Behandlung werden abgerundete, teils ergonomisch geformte Steine aus Keramik, welche auf ca. 60 Grad erwärmt sind, wird der gesamte Körper behandelt. Verspannungen und Körperblockaden können, durch den Wärme speichernden Stein, auch gezielt platziert durch Auflegen, gelöst werden. <br/><br/>Body Hot Stone ist für jedes Alter geeignet, lediglich bei Osteoporose und Schwangerschaft ist eine Behandlung nicht zu empfehlen.'
},
{
id: '3',
title: 'Tantra',
images: [
'/static/images/BodyTantra1.jpg',
'/static/images/BodyTantra2.jpg',
'/static/images/BodyTantra3.jpg',
'/static/images/BodyTantra4.jpg',
'/static/images/BodyTantra5.jpg',
'/static/images/BodyTantra6.jpg'
],
minuteOptions: [
],
addons: getAddons(['Infrarotlampe', 'BioAromaöl', 'HotBodyWachs']),
description: 'Die traditionelle Tantralehre stammt aus Indien. Entwickelt und praktiziert wurde sie vor allem zwischen 300 bis 800 nach Christus.<br/><br/>Bei BodyTantra handelt es sich um eine erotische Ganzkörperanwendung. Der gesamte Body sowie die erogenen Zonen, werden durch Berührungen/Streichungen zur Tiefenentspannung geführt und bereiten in Kombination mit stimulierenden Ölen ein wahrhaft sinnliches Körpergefühl.'
},
{
id: '4',
title: 'Klang',
images: [
'/static/images/BodyKlang1.jpg',
'/static/images/BodyKlang2.jpg',
'/static/images/BodyKlang3.jpg',
'/static/images/BodyKlang4.jpg',
'/static/images/BodyKlang5.jpg',
'/static/images/BodyKlang6.jpg'
],
minuteOptions: [
],
description: 'Tibetanische Klangschalen werden auf Deinen Body platziert. Mit einem Klöppel werden Klänge und Schwingungen an den Schalen erzeugt.<br/><br/>Body Klang Anwendung kann eine Senkung des Blutdruckes, positive Stimulierung des Immunsystems, Schmerzlinderung sowie Reduzierung von Depressionen bewirken.'
}
];
export const studios = {
wien: {
title: 'Wien',
address: '-',
addressLink: '',
description: 'Klein aber Fein in exklusivem Ambiente, so präsentiert sich unser Studio, eingebettet in ein Jugendstilhaus der Jahrhundertwende im schönen 19. Wiener Bezirk Döbling. Geöffnet am Dienstag, Mittwoch und Freitag von 13:00 bis 20:00 Uhr. Bitte Termin vereinbaren.',
images: [
'/static/images/StudioWien1.jpg',
'/static/images/StudioWien2.jpg',
'/static/images/StudioWien3.jpg',
'/static/images/StudioWien4.jpg',
'/static/images/StudioWien5.jpg',
'/static/images/StudioWien6.jpg',
'/static/images/StudioWien7.jpg',
'/static/images/StudioWien8.jpg'
]
},
niederoesterreich: {
title: 'Niederösterreich',
address: '-',
addressLink: '',
description: 'Modern und elegant präsentiert sich die Räumlichkeit bei unserem Kooperationspartner Kosmetikinstitut Liliane, Pottendorf in Niederösterreich. Nur nach vorheriger Terminvereinbarung, jeweils Donnerstag und Samstag von 8:00 bis 18:00 Uhr möglich.',
images: ['/static/images/tantracropped.jpg', '/static/images/tantracropped1.jpg']
},
};
This is my ImageReel.tsx:
import {motion} from "framer-motion";
import Image from "next/image";
export const ImageReel = ({images, speedFactor}: { images: string[], speedFactor?: number }) => {
return (
<div className={'flex justify-center gap-5 max-h-[200px] overflow-hidden'}>
<motion.div
className={'flex'}
initial={{translateX: '0%'}}
animate={{
translateX: ['0%', '-100%'],
transition: {
repeatType: 'loop',
duration: 45 / speedFactor,
repeat: Infinity,
ease: 'linear'
}
}}
style={{display: 'flex', gap: '10px'}} // Gap between images
>
{[...images, ...images].map((image, index) => (
<Image
key={index}
src={image}
width={200}
height={200}
className={'rounded-lg'}
alt={'Bild'}
style={{
maxWidth: "100%",
height: "auto",
objectFit: "cover"
}}
/>
))}
</motion.div>
</div>
);
};
My package.json:
{
"name": "body-harmony-website",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint --fix"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/pro-light-svg-icons": "^6.5.2",
"@fortawesome/pro-regular-svg-icons": "^6.5.2",
"@fortawesome/pro-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@tailwindcss/typography": "^0.5.13",
"axios": "^1.7.2",
"framer-motion": "^11.2.10",
"interweave": "^13.1.0",
"interweave-ssr": "^2.0.0",
"lottie-web": "^5.12.2",
"lucide-react": "^0.390.0",
"next": "^14.2.3",
"next-i18next": "^15.3.0",
"next-seo": "^6.5.0",
"postcss": "^8.4.38",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-lottie": "^1.2.4",
"react-swipeable": "^7.0.1",
"sharp": "^0.33.4",
"swr": "^2.2.5",
"tailwindcss": "^3.4.4"
},
"devDependencies": {
"@types/node": "^20.14.2",
"@types/react": "18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-lottie": "^1.2.10",
"autoprefixer": "10.4.19",
"eslint": "9.4.0",
"eslint-config-next": "14.2.3",
"typescript": "5.4.5"
}
}
My next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**.bodyharmoniewien.at',
port: '',
pathname: '**'
}
],
},
output: 'standalone',
async headers() {
return [
{
source: '/(.*)',
headers: securityHeaders
}
];
}
}
const ContentSecurityPolicy = `
default-src 'self';
script-src 'unsafe-eval' 'unsafe-inline' 'self';
style-src 'self' 'unsafe-inline';
img-src * blob: data: 'self' https:;
media-src 'self';
connect-src *;
worker-src 'self' blob:;
font-src 'self' data:;
`;
const securityHeaders = [
{
key: 'Content-Security-Policy',
value: ContentSecurityPolicy.replace(/n/g, '')
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin'
},
{
key: 'X-Frame-Options',
value: 'DENY'
},
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'X-DNS-Prefetch-Control',
value: 'on'
},
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains; preload'
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()'
}
];
module.exports = nextConfig
I was already checking all paths, syntax, image filenames, next.config.js file, Dockerfile, asked ChatGPT and searched Google for possible solutions, but it seems that yet nobody experienced the issue I have.
I have a thought that maybe it has something to do with the image array and that I am not doing an “import” for every single image. But this still does not explain why all images of “HotStone” treatment are showing up then.
jasonschell is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.