diff --git a/my-favorites-app/.dockerignore b/my-favorites-app/.dockerignore new file mode 100644 index 0000000..1418ed8 --- /dev/null +++ b/my-favorites-app/.dockerignore @@ -0,0 +1,33 @@ +# Versioning and metadata +.git +.gitignore +.dockerignore + +# Build dependencies +node_modules +npm-debug.log + +# Environment (contains sensitive data) +.env +.env.* +!.env.example + +# Files not required for production +README.md +Dockerfile +docker-compose.yml +*.log +.next +.vscode +.idea +*.md +*.log +*.lock + +# Testing +coverage +.nyc_output +test + +# Misc +.DS_Store diff --git a/my-favorites-app/Dockerfile b/my-favorites-app/Dockerfile new file mode 100644 index 0000000..2be358e --- /dev/null +++ b/my-favorites-app/Dockerfile @@ -0,0 +1,55 @@ +# Use Node 18 Alpine as the base image for smaller size +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package.json package-lock.json* ./ +RUN npm ci + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Set environment variables +ENV NEXT_TELEMETRY_DISABLED 1 + +# Build the application +RUN npm run build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production +ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy necessary files from the builder stage +COPY --from=builder /app/public ./public + +# Set the correct permissions +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 +ENV HOSTNAME "0.0.0.0" + +# Start the application +CMD ["node", "server.js"] diff --git a/my-favorites-app/next.config.ts b/my-favorites-app/next.config.ts index e9ffa30..3a281e9 100644 --- a/my-favorites-app/next.config.ts +++ b/my-favorites-app/next.config.ts @@ -1,7 +1,22 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + output: 'standalone', + images: { + domains: [ + 'm.media-amazon.com', + 'i.scdn.co', + 'www.moma.org' + ], + remotePatterns: [ + { + protocol: 'https', + hostname: '**', + }, + ], + }, + // Enable strict mode for better development experience + reactStrictMode: true, }; export default nextConfig; diff --git a/my-favorites-app/server.js b/my-favorites-app/server.js new file mode 100644 index 0000000..7e3faa2 --- /dev/null +++ b/my-favorites-app/server.js @@ -0,0 +1,39 @@ +const { createServer } = require('http'); +const { parse } = require('url'); +const next = require('next'); + +const dev = process.env.NODE_ENV !== 'production'; +const hostname = process.env.HOSTNAME || '0.0.0.0'; +const port = parseInt(process.env.PORT || '3000', 10); + +// Prepare the Next.js app +const app = next({ dev, hostname, port }); +const handle = app.getRequestHandler(); + +app.prepare().then(() => { + console.log(`Next.js App is preparing to start...`); + + createServer(async (req, res) => { + try { + // Parse the URL + const parsedUrl = parse(req.url, true); + + // Let Next.js handle the request + await handle(req, res, parsedUrl); + } catch (err) { + console.error('Error occurred handling request:', err); + res.statusCode = 500; + res.end('Internal Server Error'); + } + }) + .once('error', (err) => { + console.error('Server error:', err); + process.exit(1); + }) + .listen(port, hostname, () => { + console.log(`> Ready on http://${hostname}:${port}`); + }); +}).catch((err) => { + console.error('Next.js app preparation failed:', err); + process.exit(1); +}); diff --git a/my-favorites-app/src/app/api/health/route.ts b/my-favorites-app/src/app/api/health/route.ts new file mode 100644 index 0000000..3ec01eb --- /dev/null +++ b/my-favorites-app/src/app/api/health/route.ts @@ -0,0 +1,5 @@ +import { NextResponse } from 'next/server'; + +export async function GET() { + return NextResponse.json({ status: 'ok', timestamp: new Date().toISOString() }); +}