From 09add3b0504d39c73fc7d48a1b711e703a93b733 Mon Sep 17 00:00:00 2001 From: Max Proske Date: Sun, 27 Nov 2022 16:13:22 -0800 Subject: [PATCH] Fix `with-docker-compose` example (#43419) 1. Fixes example unable to build with the latest version of Next. - Next.js 13 bumped the minimum React version to [18.2.0](https://nextjs.org/docs/upgrading), but this example seems to have gotten missed. 2. Fixes example unable to run by default on Linux. - Reverts #39372 - Fixes @balazsorban44 comment https://github.com/vercel/next.js/pull/39372#issuecomment-1208012860 - Added a comment to the README to prevent this issue from being re-introduced. 3. Build and start Next.js based on the preferred package manager. 4. Allow dependencies to install without lockfile present. - Outputs a warning instead of exiting. - Keeps the example faithful to the README "Develop locally without Node.js or TypeScript installed". 5. Added `next.config.js` types that got missed. 6. Updated README links now that output standalone is stable. ## Documentation / Examples - [X] Make sure the linting passes by running `pnpm build && pnpm lint` - [X] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- examples/with-docker-compose/README.md | 35 +++++++++++-------- .../next-app/dev.Dockerfile | 17 +++++++-- .../next-app/next.config.js | 5 ++- .../with-docker-compose/next-app/package.json | 12 +++---- .../prod-without-multistage.Dockerfile | 22 ++++++++++-- .../next-app/prod.Dockerfile | 17 +++++++-- 6 files changed, 79 insertions(+), 29 deletions(-) diff --git a/examples/with-docker-compose/README.md b/examples/with-docker-compose/README.md index d4e1458abd33..088d112c816d 100644 --- a/examples/with-docker-compose/README.md +++ b/examples/with-docker-compose/README.md @@ -5,10 +5,9 @@ This example contains everything needed to get a Next.js development and product ## Benefits of Docker Compose - Develop locally without Node.js or TypeScript installed ✨ -- Easy to run, consistent development environment across Mac, Windows, and Linux teams +- Easy to run, consistent development environment across macOS, Windows, and Linux teams - Run multiple Next.js apps, databases, and other microservices in a single deployment -- Multistage builds combined with [Output Standalone](https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files-experimental) outputs up to 85% smaller apps (Approximately 110 MB compared to 1 GB with create-next-app) -- BuildKit engine builds multiple Docker images in parallel +- Multistage builds combined with [Output Standalone](https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files) outputs up to 85% smaller apps (Approximately 110 MB compared to 1 GB with create-next-app) - Easy configuration with YAML files ## How to use @@ -27,6 +26,12 @@ yarn create next-app --example with-docker-compose with-docker-compose-app pnpm create next-app --example with-docker-compose with-docker-compose-app ``` +Optionally, after the installation is complete: + +- Run `cd next-app`, then run `npm install` or `yarn install` or `pnpm install` to generate a lockfile. + +It is recommended to commit a lockfile to version control. Although the example will work without one, build errors are more likely to occur when using the latest version of all dependencies. This way, we're always using a known good configuration to develop and run in production. + ## Prerequisites Install [Docker Desktop](https://docs.docker.com/get-docker) for Mac, Windows, or Linux. Docker Desktop includes Docker Compose as part of the installation. @@ -40,11 +45,13 @@ First, run the development server: # with each other, by using their container name as a hostname docker network create my_network -# Build dev using new BuildKit engine -docker compose -f docker-compose.dev.yml build +# Build dev +# Note: Keep v1 command until "Use Docker Compose v2" is enabled by default for Docker Desktop for Linux +# Docker aliases `docker-compose` (v1 command) to `docker compose` (v2 command), but not the other way around +docker-compose -f docker-compose.dev.yml build # Up dev -docker compose -f docker-compose.dev.yml up +docker-compose -f docker-compose.dev.yml up ``` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. @@ -53,7 +60,7 @@ You can start editing the page by modifying `pages/index.tsx`. The page auto-upd ## Production -Multistage builds are highly recommended in production. Combined with the Next 12 [Output Standalone](https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files-experimental) feature, only `node_modules` files required for production are copied into the final Docker image. +Multistage builds are highly recommended in production. Combined with the Next [Output Standalone](https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files) feature, only `node_modules` files required for production are copied into the final Docker image. First, run the production server (Final image approximately 110 MB). @@ -62,11 +69,11 @@ First, run the production server (Final image approximately 110 MB). # with each other, by using their container name as a hostname docker network create my_network -# Build prod using new BuildKit engine -docker compose -f docker-compose.prod.yml build +# Build prod +docker-compose -f docker-compose.prod.yml build # Up prod in detached mode -docker compose -f docker-compose.prod.yml up -d +docker-compose -f docker-compose.prod.yml up -d ``` Alternatively, run the production server without without multistage builds (Final image approximately 1 GB). @@ -76,11 +83,11 @@ Alternatively, run the production server without without multistage builds (Fina # with each other, by using their container name as a hostname docker network create my_network -# Build prod without multistage using new BuildKit engine -docker compose -f docker-compose.prod-without-multistage.yml build +# Build prod without multistage +docker-compose -f docker-compose.prod-without-multistage.yml build # Up prod without multistage in detached mode -docker compose -f docker-compose.prod-without-multistage.yml up -d +docker-compose -f docker-compose.prod-without-multistage.yml up -d ``` Open [http://localhost:3000](http://localhost:3000). @@ -89,7 +96,7 @@ Open [http://localhost:3000](http://localhost:3000). ```bash # Stop all running containers -docker kill $(docker ps -q) && docker rm $(docker ps -a -q) +docker kill $(docker ps -aq) && docker rm $(docker ps -aq) # Free space docker system prune -af --volumes diff --git a/examples/with-docker-compose/next-app/dev.Dockerfile b/examples/with-docker-compose/next-app/dev.Dockerfile index fbba79e67541..e46c559e33c9 100644 --- a/examples/with-docker-compose/next-app/dev.Dockerfile +++ b/examples/with-docker-compose/next-app/dev.Dockerfile @@ -8,7 +8,8 @@ RUN \ if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ elif [ -f package-lock.json ]; then npm ci; \ elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \ - else echo "Lockfile not found." && exit 1; \ + # Allow install without lockfile, so example works even without Node.js installed locally + else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \ fi COPY src ./src @@ -16,4 +17,16 @@ COPY public ./public COPY next.config.js . COPY tsconfig.json . -CMD yarn dev +# Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry +# Uncomment the following line to disable telemetry at run time +# ENV NEXT_TELEMETRY_DISABLED 1 + +# Note: Don't expose ports here, Compose will handle that for us + +# Start Next.js in development mode based on the preferred package manager +CMD \ + if [ -f yarn.lock ]; then yarn dev; \ + elif [ -f package-lock.json ]; then npm run dev; \ + elif [ -f pnpm-lock.yaml ]; then pnpm dev; \ + else yarn dev; \ + fi diff --git a/examples/with-docker-compose/next-app/next.config.js b/examples/with-docker-compose/next-app/next.config.js index e97173b4b379..5cd8cc341fdc 100644 --- a/examples/with-docker-compose/next-app/next.config.js +++ b/examples/with-docker-compose/next-app/next.config.js @@ -1,3 +1,6 @@ -module.exports = { +/** @type {import('next').NextConfig} */ +const nextConfig = { output: 'standalone', } + +module.exports = nextConfig diff --git a/examples/with-docker-compose/next-app/package.json b/examples/with-docker-compose/next-app/package.json index 2a67a59e0f83..2252065ea0d9 100644 --- a/examples/with-docker-compose/next-app/package.json +++ b/examples/with-docker-compose/next-app/package.json @@ -7,13 +7,13 @@ }, "dependencies": { "next": "latest", - "react": "18.1.0", - "react-dom": "18.1.0" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { - "@types/node": "17.0.42", - "@types/react": "18.0.12", - "@types/react-dom": "18.0.5", - "typescript": "4.7.3" + "@types/node": "^18.11.9", + "@types/react": "^18.0.25", + "@types/react-dom": "^18.0.9", + "typescript": "^4.9.3" } } diff --git a/examples/with-docker-compose/next-app/prod-without-multistage.Dockerfile b/examples/with-docker-compose/next-app/prod-without-multistage.Dockerfile index 54a9fde2f118..e17d8765e337 100644 --- a/examples/with-docker-compose/next-app/prod-without-multistage.Dockerfile +++ b/examples/with-docker-compose/next-app/prod-without-multistage.Dockerfile @@ -9,7 +9,8 @@ RUN \ if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ elif [ -f package-lock.json ]; then npm ci; \ elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \ - else echo "Lockfile not found." && exit 1; \ + # Allow install without lockfile, so example works even without Node.js installed locally + else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \ fi COPY src ./src @@ -24,9 +25,24 @@ ENV ENV_VARIABLE=${ENV_VARIABLE} ARG NEXT_PUBLIC_ENV_VARIABLE ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE} +# Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry # Uncomment the following line to disable telemetry at build time # ENV NEXT_TELEMETRY_DISABLED 1 -RUN yarn build +# Note: Don't expose ports here, Compose will handle that for us -CMD yarn start +# Build Next.js based on the preferred package manager +RUN \ + if [ -f yarn.lock ]; then yarn build; \ + elif [ -f package-lock.json ]; then npm run build; \ + elif [ -f pnpm-lock.yaml ]; then pnpm build; \ + else yarn build; \ + fi + +# Start Next.js based on the preferred package manager +CMD \ + if [ -f yarn.lock ]; then yarn start; \ + elif [ -f package-lock.json ]; then npm run start; \ + elif [ -f pnpm-lock.yaml ]; then pnpm start; \ + else yarn start; \ + fi diff --git a/examples/with-docker-compose/next-app/prod.Dockerfile b/examples/with-docker-compose/next-app/prod.Dockerfile index 789611143c20..3c730c626654 100644 --- a/examples/with-docker-compose/next-app/prod.Dockerfile +++ b/examples/with-docker-compose/next-app/prod.Dockerfile @@ -10,10 +10,10 @@ RUN \ if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ elif [ -f package-lock.json ]; then npm ci; \ elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \ - else echo "Lockfile not found." && exit 1; \ + # Allow install without lockfile, so example works even without Node.js installed locally + else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \ fi - COPY src ./src COPY public ./public COPY next.config.js . @@ -26,10 +26,19 @@ ENV ENV_VARIABLE=${ENV_VARIABLE} ARG NEXT_PUBLIC_ENV_VARIABLE ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE} +# Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry # Uncomment the following line to disable telemetry at build time # ENV NEXT_TELEMETRY_DISABLED 1 -RUN yarn build +# Build Next.js based on the preferred package manager +RUN \ + if [ -f yarn.lock ]; then yarn build; \ + elif [ -f package-lock.json ]; then npm run build; \ + elif [ -f pnpm-lock.yaml ]; then pnpm build; \ + else yarn build; \ + fi + +# Note: It is not necessary to add an intermediate step that does a full copy of `node_modules` here # Step 2. Production image, copy all the files and run next FROM node:18-alpine AS runner @@ -57,4 +66,6 @@ ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE} # Uncomment the following line to disable telemetry at run time # ENV NEXT_TELEMETRY_DISABLED 1 +# Note: Don't expose ports here, Compose will handle that for us + CMD node server.js