diff --git a/gdf.js b/gdf.js index 9964ecf..e02405e 100755 --- a/gdf.js +++ b/gdf.js @@ -203,23 +203,28 @@ export class GDF { // Experimental nextjs generation? get nextjsGeneration() { if (!this.nextjs) return false - if (!this.#pj.scripts.build === 'next build') return false - if (!this.#pj.dependencies.next) return false + // only `next build`, optionally with flags; anything more is a custom build + if (!/^next build(\s+-[-\w=.]+)*$/.test(this.#pj.scripts?.build?.trim() ?? '')) return false + // standalone images contain neither the next CLI nor the sources + if (this.standaloneNextjs) return false const version = this.#pj.dependencies.next.match(/\d[.\d]*/) - if (!version || version[0] < '14.2') return false + if (!version) return false + const [major, minor = 0] = version[0].split('.').map(Number) + if (major < 14 || (major === 14 && minor < 2)) return false return true } get standaloneNextjs() { if (!this.nextjs) return false - if (fs.existsSync(path.join(this._appdir, 'next.config.mjs'))) { - const config = fs.readFileSync(path.join(this._appdir, 'next.config.mjs'), 'utf-8') + for (const ext of ['mjs', 'js', 'cjs', 'ts', 'mts']) { + const file = path.join(this._appdir, `next.config.${ext}`) + if (!fs.existsSync(file)) continue + const config = fs.readFileSync(file, 'utf-8') return /output\s*:\s*(["'`])standalone\1/.test(config) - } else if (fs.existsSync(path.join(this._appdir, 'next.config.js'))) { - const config = fs.readFileSync(path.join(this._appdir, 'next.config.js'), 'utf-8') - return /output\s*:\s*(["'`])standalone\1/.test(config) - } else return false + } + + return false } // Does this application use trpc? diff --git a/test/frameworks/next-build-flags/.dockerignore b/test/frameworks/next-build-flags/.dockerignore new file mode 100644 index 0000000..fd3dbb5 --- /dev/null +++ b/test/frameworks/next-build-flags/.dockerignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/test/frameworks/next-build-flags/Dockerfile b/test/frameworks/next-build-flags/Dockerfile new file mode 100644 index 0000000..07ada70 --- /dev/null +++ b/test/frameworks/next-build-flags/Dockerfile @@ -0,0 +1,48 @@ +# syntax = docker/dockerfile:1 + +# Adjust NODE_VERSION as desired +ARG NODE_VERSION=xxx +FROM node:${NODE_VERSION}-slim AS base + +LABEL fly_launch_runtime="Next.js" + +# Next.js app lives here +WORKDIR /app + +# Set production environment +ENV NODE_ENV="production" + + +# Throw-away build stage to reduce size of final image +FROM base AS build + +# Install packages needed to build node modules +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3 + +# Install node modules +COPY package-lock.json package.json ./ +RUN npm ci --include=dev + +# Copy application code +COPY . . + +# Build application +RUN npx next build --experimental-build-mode compile + +# Remove development dependencies +RUN npm prune --omit=dev + + +# Final stage for app image +FROM base + +# Copy built application +COPY --from=build /app /app + +# Entrypoint sets up the container. +ENTRYPOINT [ "/app/docker-entrypoint.js" ] + +# Start the server by default, this can be overwritten at runtime +EXPOSE 3000 +CMD [ "npm", "run", "start" ] diff --git a/test/frameworks/next-standalone/docker-entrypoint.js b/test/frameworks/next-build-flags/docker-entrypoint.js similarity index 90% rename from test/frameworks/next-standalone/docker-entrypoint.js rename to test/frameworks/next-build-flags/docker-entrypoint.js index 91b89a3..49e5199 100755 --- a/test/frameworks/next-standalone/docker-entrypoint.js +++ b/test/frameworks/next-build-flags/docker-entrypoint.js @@ -6,7 +6,7 @@ const env = { ...process.env } ;(async() => { // If running the web server then prerender pages - if (process.argv.slice(-2).join(' ') === 'node server.js') { + if (process.argv.slice(-3).join(' ') === 'npm run start') { await exec('npx next build --experimental-build-mode generate') } diff --git a/test/frameworks/next-build-flags/package-lock.json b/test/frameworks/next-build-flags/package-lock.json new file mode 100644 index 0000000..0985ee8 --- /dev/null +++ b/test/frameworks/next-build-flags/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "standalone-next-js-test", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/test/frameworks/next-build-flags/package.json b/test/frameworks/next-build-flags/package.json new file mode 100644 index 0000000..349e21f --- /dev/null +++ b/test/frameworks/next-build-flags/package.json @@ -0,0 +1,27 @@ +{ + "name": "standalone-next-js-test", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build --turbopack", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "next": "14.2.1", + "react": "^18", + "react-dom": "^18" + }, + "devDependencies": { + "@flydotio/dockerfile": "^0.5.5", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "14.2.1", + "postcss": "^8", + "tailwindcss": "^3.4.1", + "typescript": "^5" + } +} diff --git a/test/frameworks/next-custom-build/.dockerignore b/test/frameworks/next-custom-build/.dockerignore new file mode 100644 index 0000000..fd3dbb5 --- /dev/null +++ b/test/frameworks/next-custom-build/.dockerignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/test/frameworks/next-custom-build/Dockerfile b/test/frameworks/next-custom-build/Dockerfile new file mode 100644 index 0000000..c06933a --- /dev/null +++ b/test/frameworks/next-custom-build/Dockerfile @@ -0,0 +1,45 @@ +# syntax = docker/dockerfile:1 + +# Adjust NODE_VERSION as desired +ARG NODE_VERSION=xxx +FROM node:${NODE_VERSION}-slim AS base + +LABEL fly_launch_runtime="Next.js" + +# Next.js app lives here +WORKDIR /app + +# Set production environment +ENV NODE_ENV="production" + + +# Throw-away build stage to reduce size of final image +FROM base AS build + +# Install packages needed to build node modules +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3 + +# Install node modules +COPY package-lock.json package.json ./ +RUN npm ci --include=dev + +# Copy application code +COPY . . + +# Build application +RUN npm run build + +# Remove development dependencies +RUN npm prune --omit=dev + + +# Final stage for app image +FROM base + +# Copy built application +COPY --from=build /app /app + +# Start the server by default, this can be overwritten at runtime +EXPOSE 3000 +CMD [ "npm", "run", "start" ] diff --git a/test/frameworks/next-custom-build/package-lock.json b/test/frameworks/next-custom-build/package-lock.json new file mode 100644 index 0000000..0985ee8 --- /dev/null +++ b/test/frameworks/next-custom-build/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "standalone-next-js-test", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/test/frameworks/next-custom-build/package.json b/test/frameworks/next-custom-build/package.json new file mode 100644 index 0000000..540d510 --- /dev/null +++ b/test/frameworks/next-custom-build/package.json @@ -0,0 +1,27 @@ +{ + "name": "standalone-next-js-test", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build && node scripts/postbuild.js", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "next": "14.2.1", + "react": "^18", + "react-dom": "^18" + }, + "devDependencies": { + "@flydotio/dockerfile": "^0.5.5", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "14.2.1", + "postcss": "^8", + "tailwindcss": "^3.4.1", + "typescript": "^5" + } +} diff --git a/test/frameworks/next-standalone-ts/.dockerignore b/test/frameworks/next-standalone-ts/.dockerignore new file mode 100644 index 0000000..fd3dbb5 --- /dev/null +++ b/test/frameworks/next-standalone-ts/.dockerignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/test/frameworks/next-standalone-ts/Dockerfile b/test/frameworks/next-standalone-ts/Dockerfile new file mode 100644 index 0000000..a6afec8 --- /dev/null +++ b/test/frameworks/next-standalone-ts/Dockerfile @@ -0,0 +1,47 @@ +# syntax = docker/dockerfile:1 + +# Adjust NODE_VERSION as desired +ARG NODE_VERSION=xxx +FROM node:${NODE_VERSION}-slim AS base + +LABEL fly_launch_runtime="Next.js" + +# Next.js app lives here +WORKDIR /app + +# Set production environment +ENV NODE_ENV="production" + + +# Throw-away build stage to reduce size of final image +FROM base AS build + +# Install packages needed to build node modules +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3 + +# Install node modules +COPY package-lock.json package.json ./ +RUN npm ci --include=dev + +# Copy application code +COPY . . + +# Build application +RUN npm run build + +# Remove development dependencies +RUN npm prune --omit=dev + + +# Final stage for app image +FROM base + +# Copy built application +COPY --from=build /app/.next/standalone /app +COPY --from=build /app/.next/static /app/.next/static +COPY --from=build /app/public /app/public + +# Start the server by default, this can be overwritten at runtime +EXPOSE 3000 +CMD [ "node", "server.js" ] diff --git a/test/frameworks/next-standalone-ts/next.config.ts b/test/frameworks/next-standalone-ts/next.config.ts new file mode 100644 index 0000000..bff4933 --- /dev/null +++ b/test/frameworks/next-standalone-ts/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + output: "standalone" +}; + +export default nextConfig; diff --git a/test/frameworks/next-standalone-ts/package-lock.json b/test/frameworks/next-standalone-ts/package-lock.json new file mode 100644 index 0000000..0985ee8 --- /dev/null +++ b/test/frameworks/next-standalone-ts/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "standalone-next-js-test", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/test/frameworks/next-standalone-ts/package.json b/test/frameworks/next-standalone-ts/package.json new file mode 100644 index 0000000..90a413d --- /dev/null +++ b/test/frameworks/next-standalone-ts/package.json @@ -0,0 +1,27 @@ +{ + "name": "standalone-next-js-test", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "next": "14.2.1", + "react": "^18", + "react-dom": "^18" + }, + "devDependencies": { + "@flydotio/dockerfile": "^0.5.5", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "14.2.1", + "postcss": "^8", + "tailwindcss": "^3.4.1", + "typescript": "^5" + } +} diff --git a/test/frameworks/next-standalone/Dockerfile b/test/frameworks/next-standalone/Dockerfile index f22ed4e..a6afec8 100644 --- a/test/frameworks/next-standalone/Dockerfile +++ b/test/frameworks/next-standalone/Dockerfile @@ -28,7 +28,7 @@ RUN npm ci --include=dev COPY . . # Build application -RUN npx next build --experimental-build-mode compile +RUN npm run build # Remove development dependencies RUN npm prune --omit=dev @@ -42,9 +42,6 @@ COPY --from=build /app/.next/standalone /app COPY --from=build /app/.next/static /app/.next/static COPY --from=build /app/public /app/public -# Entrypoint sets up the container. -ENTRYPOINT [ "/app/docker-entrypoint.js" ] - # Start the server by default, this can be overwritten at runtime EXPOSE 3000 CMD [ "node", "server.js" ]