diff --git a/.dockerignore b/.dockerignore index 3a2d949a..83de55cd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,10 +1,52 @@ # .dockerignore is used to exclude files and directories from being copied into the Docker image during the build process. This helps to reduce the size of the image and improve build times by only including necessary files. # keep it at the root of the project to ensure that we don't copy unnecessary files into the Docker image. -node_modules -**/.turbo +# git (disable if needed in the container) +.git + +# dependencies +**/node_modules + +# caches **/.cache +**/tsconfig.tsbuildinfo +**/tsconfig.*.tsbuildinfo +**/.eslintcache + +# turbo (comment if you want to copy the turbo cache into the image) +**/.turbo + +# package managers +**/.yarn/* +!**/.yarn/patches +!**/.yarn/releases +!**/.yarn/plugins +.pnp.* + +# testing +**/coverage +**/.out/ + +# Build directories **/apps/*/.next **/packages/*/dist **/packages/*/docs -**/.eslintcache + +# Misc +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# IDE +.idea/* +.project +.classpath +*.launch +*.sublime-workspace +.vscode/ + + diff --git a/.gitignore b/.gitignore index ac065e4c..e5f4487b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ _release # Turbo pruned files -out +.turbo-pruned # local env files (following nextjs convention) diff --git a/examples/apps/nextjs-app/docker/.dockerignore b/examples/apps/nextjs-app/docker/.dockerignore index 5fd6ba02..a1473d71 100644 --- a/examples/apps/nextjs-app/docker/.dockerignore +++ b/examples/apps/nextjs-app/docker/.dockerignore @@ -1,10 +1,51 @@ # this file should won't be read unless it exists in the # context directory specified in the docker compose file -node_modules -#**/.turbo -#**/.cache -#**/apps/*/.next -#**/packages/*/dist -#**/packages/*/docs -#**/.eslintcache \ No newline at end of file +# git (disable if needed in the container) +.git + +# dependencies +**/node_modules + +# caches +**/.cache +**/tsconfig.tsbuildinfo +**/tsconfig.*.tsbuildinfo +**/.eslintcache + +# turbo (comment if you want to copy the turbo cache into the image) +**/.turbo + +# package managers +**/.yarn/* +!**/.yarn/patches +!**/.yarn/releases +!**/.yarn/plugins +.pnp.* + +# testing +**/coverage +**/.out/ + +# Build directories +**/apps/*/.next +**/packages/*/dist +**/packages/*/docs + +# Misc +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# IDE +.idea/* +.project +.classpath +*.launch +*.sublime-workspace +.vscode/ + diff --git a/examples/apps/nextjs-app/docker/Dockerfile b/examples/apps/nextjs-app/docker/Dockerfile index 17bb0dc6..84573b80 100644 --- a/examples/apps/nextjs-app/docker/Dockerfile +++ b/examples/apps/nextjs-app/docker/Dockerfile @@ -27,7 +27,7 @@ RUN TURBO_VERSION=$(cat package.json | jq '.devDependencies["turbo"]' -r) npm i COPY --link . . # https://turbo.build/repo/docs/handbook/deploying-with-docker -RUN turbo prune --scope=@examples/nextjs-app --docker --out-dir=./out/nextjs-app/ +RUN turbo prune --scope=@examples/nextjs-app --docker --out-dir=./.turbo-pruned/nextjs-app/ ############################################################# # Stage 2 - App installation # @@ -57,8 +57,8 @@ WORKDIR /app # First install the dependencies (as they change less often) COPY --link .gitignore ./ -COPY --from=prepare --link /app/out/nextjs-app/json/ . -COPY --from=prepare --link /app/out/nextjs-app/yarn.lock ./yarn.lock +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/json/ . +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/yarn.lock ./yarn.lock # Option 1: run install without cache #RUN yarn install --inline-builds @@ -69,7 +69,7 @@ RUN --mount=type=cache,target=/root/.yarn3-cache,id=yarn3-cache,sharing=locked \ yarn install --inline-builds # Build the project -COPY --link --from=prepare /app/out/nextjs-app/full/ . +COPY --link --from=prepare /app/.turbo-pruned/nextjs-app/full/ . COPY --link .gitignore turbo.jsonc tsconfig.base.json ./ ENV NEXT_BUILD_IGNORE_ESLINT=true @@ -101,20 +101,19 @@ ENV NODE_ENV=production RUN apt-get update \ && apt-get install bash tzdata --no-install-recommends -y \ - && rm -rf /var/cache/apt/* \ + && rm -rf /var/cache/apt/* # If needed, we can enable corepack in the runner as well, but for now we don't need it \ # since we're running the built server.js directly with node. - && npm i -g corepack@${COREPACK_VERSION} && corepack enable + # && npm i -g corepack@${COREPACK_VERSION} && corepack enable WORKDIR /app -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs - # Set the correct permission for prerender cache -RUN mkdir .next -RUN chown nextjs:nodejs .next +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs \ + && mkdir .next \ + && chown nextjs:nodejs .next USER nextjs diff --git a/examples/apps/nextjs-app/docker/Dockerfile.distroless b/examples/apps/nextjs-app/docker/Dockerfile.distroless new file mode 100644 index 00000000..abc0b914 --- /dev/null +++ b/examples/apps/nextjs-app/docker/Dockerfile.distroless @@ -0,0 +1,133 @@ +ARG NODE_VERSION=24.14 +ARG DISTROLESS_IMAGE=gcr.io/distroless/nodejs24-debian13 +ARG DEBIAN_VERSION=trixie-slim +ARG COREPACK_VERSION=0.34.6 + + +############################################################# +# Stage 1 - App extraction / pruning # +############################################################# + +FROM node:${NODE_VERSION}-${DEBIAN_VERSION} AS prepare + +RUN apt-get update \ + #&& apt-get install build-essential cmake curl unzip ca-certificates git jq --no-install-recommends -y \ + && apt-get install git jq --no-install-recommends -y \ + && rm -rf /var/cache/apt/* \ + ## Corepack won't be bundled in node 25+ + && npm i -g corepack@${COREPACK_VERSION} && corepack enable + + +WORKDIR /app + +COPY --link package.json turbo.jsonc ./ + +# We can't run turbo without yarn install first, let's install locally and make sure +# both local and docker are aligned on the package.json version. +RUN TURBO_VERSION=$(cat package.json | jq '.devDependencies["turbo"]' -r) npm i -g turbo@${TURBO_VERSION} + +COPY --link . . + +# https://turbo.build/repo/docs/handbook/deploying-with-docker +RUN turbo prune --scope=@examples/nextjs-app --docker --out-dir=./.turbo-pruned/nextjs-app/ + +############################################################# +# Stage 2 - App installation # +############################################################# + +FROM prepare AS builder + +ENV TZ=Etc/UTC + +# Optimize for YARN installation speed +ENV YARN_ENABLE_GLOBAL_CACHE=false +ENV YARN_ENABLE_MIRROR=false +ENV YARN_ENABLE_TELEMETRY=false +ENV YARN_NODE_LINKER=node-modules +ENV YARN_NM_MODE=hardlinks-local +ENV YARN_ENABLE_HARDENED_MODE=0 +ENV YARN_ENABLE_CONSTRAINTS_CHECKS=false +# If using different compression level than in local (recommended: prefer to not do this) +#ENV YARN_COMPRESSION_LEVEL 0 +#ENV YARN_CHECKSUM_BEHAVIOR ignore + +# Disabling some well-known postinstall scripts +ENV PRISMA_SKIP_POSTINSTALL_GENERATE=true +ENV HUSKY=0 + +WORKDIR /app + +# First install the dependencies (as they change less often) +COPY --link .gitignore ./ +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/json/ . +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/yarn.lock ./yarn.lock + +# Option 1: run install without cache +#RUN yarn install --inline-builds + +# Option 2: run install with buildx cache mount (buildx) +RUN --mount=type=cache,target=/root/.yarn3-cache,id=yarn3-cache,sharing=locked \ + YARN_CACHE_FOLDER=/root/.yarn3-cache \ + yarn install --inline-builds + +# Build the project +COPY --link --from=prepare /app/.turbo-pruned/nextjs-app/full/ . +COPY --link .gitignore turbo.jsonc tsconfig.base.json ./ + +ENV NEXT_BUILD_IGNORE_ESLINT=true +ENV NEXT_BUILD_IGNORE_TYPECHECK=true +ENV NEXT_BUILD_OUTPUT=standalone +ENV NODE_ENV=production +# ENV NEXT_BUILD_ENV_SENTRY_ENABLED=false +# ENV NEXT_BUILD_ENV_SENTRY_TRACING=false + +RUN yarn workspace @examples/db-sqlserver prisma-generate + +RUN yarn turbo run build --filter=@examples/nextjs-app +# Alternative we can also +#RUN yarn turbo run build --filter=@examples/nextjs-app... + +############################################################# +# Stage 3 - App runner # +############################################################# + +FROM ${DISTROLESS_IMAGE} AS runner + +ARG NEXTJS_APP_PORT + +# Bort PORT / HOSTNAME envs are respected by nextjs start/dev. +ENV HOSTNAME=0.0.0.0 +ENV PORT=${NEXTJS_APP_PORT:-3000} +ENV TZ=Etc/UTC +ENV NODE_ENV=production + +#RUN apt-get update \ +# && apt-get install tzdata --no-install-recommends -y \ +# && rm -rf /var/cache/apt/* + +WORKDIR /app + +#RUN addgroup --system --gid 1001 nodejs +#RUN adduser --system --uid 1001 nextjs + +# Set the correct permission for prerender cache +#RUN mkdir .next +#RUN chown nextjs:nodejs .next + +# Default distroless user +USER 65532:65532 + +COPY --from=builder /app/examples/apps/nextjs-app/next.config.mjs \ + /app/examples/apps/nextjs-app/package.json --chown=65532:65532 \ + ./ + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=65532:65532 /app/examples/apps/nextjs-app/.next/standalone ./ +COPY --from=builder --chown=65532:65532 /app/examples/apps/nextjs-app/.next/static ./examples/apps/nextjs-app/.next/static +COPY --from=builder --chown=65532:65532 /app/examples/apps/nextjs-app/public ./examples/apps/nextjs-app/public + +EXPOSE ${PORT} + +CMD ["node", "examples/apps/nextjs-app/server.js"] + diff --git a/examples/apps/nextjs-app/docker/docker-compose.distroless.yml b/examples/apps/nextjs-app/docker/docker-compose.distroless.yml new file mode 100644 index 00000000..f5450deb --- /dev/null +++ b/examples/apps/nextjs-app/docker/docker-compose.distroless.yml @@ -0,0 +1,17 @@ +name: flowblade-example-nextjs +services: + app-distroless: + build: + # Start from root of the monorepo + context: ../../../../ + dockerfile: ./examples/apps/nextjs-app/docker/Dockerfile.distroless + restart: no + networks: + - flowblade-net + ports: + - 3000:3000 + +networks: + flowblade-net: + driver: bridge + enable_ipv6: false diff --git a/examples/apps/nextjs-app/next.config.mjs b/examples/apps/nextjs-app/next.config.mjs index 91e8ea3d..9a58f3f8 100644 --- a/examples/apps/nextjs-app/next.config.mjs +++ b/examples/apps/nextjs-app/next.config.mjs @@ -62,43 +62,6 @@ let nextConfig = { }, }, - /* - turbopack: { - rules: { - '*.wasm': { - loaders: [ - { - loader: 'file-loader', - options: { - esModule: true, - }, - }, - ], - as: '*.js', - }, - }, - }, */ - - /* - webpack: (config, { isServer }) => { - config.module.rules.push({ - test: /\.wasm/, - loader: 'file-loader', - options: {}, - }); - - config.experiments = { - ...config.experiments, - asyncWebAssembly: true, // Enable async WebAssembly support - }; - - // config.module.rules.push({ - // test: /\.wasm$/, - // type: 'asset/resource', // Treat .wasm files as assets - // }); - return config; - }, */ - async headers() { return [ {