6import * as fs from 'fs' 7import * as _ from 'lodash-es' 26const withStandalone = cliFlag('--withStandalone'), withTurbo = cliFlag('--withTurbo'), freshCache = cliFlag('--freshCache') 28const yarnishFileNames = (() => { 29 if ((npmName as string) == 'yarn') return ['yarn.lock'] 30 if (npmName == 'pnpm') return [ 34 throw new PtErr('npmName', {npmName}) 37export const globalDependPaths = [ 41 'pnpm-workspace.yaml', 45export const dockerBuildAndRet = async ({ 51 reqDockPush?: boolean, 54 const {action, git_repo_name, dockreg_host, dockLanHost, dfLabel, cluster_name, gitsshHost, gitsshRepoPath} = _.merge(getKlusterCtx(), props) as Record<string, string> 57 const {git_sha, kanikoClusterName, name: _name} = _.merge(getAppCfg(), props) as Record<string, string> 59 const {repo_name_tag, push_repo_name_tag, dockerfileContent, tarSpecsA, includeShaInTag} = await dfToBuild.getRnt() 65 name, action, repo_name_tag: push_repo_name_tag, git_sha, dfLabel, 66 dockerfileContent, tarSpecsA, git_repo_name, dockreg_host, dockLanHost, 67 cluster_name: kanikoClusterName || cluster_name, reqDockPush, 68 gitsshHost, gitsshRepoPath, includeShaInTag: includeShaInTag as boolean | undefined, 70 if (buildResult?.imageReused) dfToBuild.imageReused = true 76const nextPath = {pnpm: 'npx next', yarn: '../../node_modules/.bin/next'}[npmName] 79export const dockerFileNextBuild = async ({aptPkgNames, dockerEnv, afterYarnInstallDockPathsA}: { 80 aptPkgNames?: string[], dockerEnv: Record<string, string>, afterYarnInstallDockPathsA: string[], 82 const {appPath} = nextDeployCtx.getStore() as {appPath: string, prebuildEnvConfH?: Record<string, string>} 84 // includeShaInTag: true ensures NEXT_PUBLIC_GIT_SHA is included in image tag hash 85 // this makes nextbuild rebuild when app code changes (filtered by import tree) 86 const dockFile = await getDockerBaseStr({afterYarnInstallDockPathsA, appPath, aptPkgNames, includeShaInTag: true}) 88 const {pushLine} = dockFile 91 const nextCacheDir = appDir + '/.next/cache' 93 pushLine(`WORKDIR ${appDir}`) 94 pushLine(`ENV ISNEXTBUILD=1`) 95 if (withStandalone) pushLine(`ENV NEXT_STANDALONE=1`) 96 const nextBuildHeapMb = getAppCfg().nextBuildHeapMb || 2048 97 dockFile.pushEnv('NODE_OPTIONS', `--no-warnings=ExperimentalWarning --max-old-space-size=${nextBuildHeapMb}`, {append: true}) 100 let workerContentHash = '' 101 if (builtWorkerFilename) { 102 const workerAbsPath = `${ptDir}/${appPath}/public/${builtWorkerFilename}` 103 if (fs.existsSync(workerAbsPath)) { 110 _.get(nextDeployCtx.getStore(), 'prebuildEnvConfH'), 113 withStandalone ? 'standalone' : '', 114 withTurbo ? 'turbo' : '', 117 // webpack fs cache hard-links into node_modules; overlayfs can't extract cross-dir hard links during pull → ErrImagePull 118 // in-progress marker: a killed build leaves the marker in the PVC-backed cache mount → next build wipes & starts cold. 119 // idempotent self-heal — no manual PVC surgery needed after a timeout/eviction mid-build. 120 const cacheGuard = `mkdir -p ${nextCacheDir} && { ${freshCache ? 'true' : `[ -f ${nextCacheDir}/.ptbuild-inprogress ]`} && find ${nextCacheDir} -mindepth 1 -delete || true; } && touch ${nextCacheDir}/.ptbuild-inprogress` 123 `echo ${dockerCacheKey}`, 124 `${nextPath} build${withTurbo ? ' --turbo' : ''}`, 125 `find ${nextCacheDir} -type f -links +1 -exec sh -c 'cp "$1" "$1.bak" && mv "$1.bak" "$1"' _ {} \\;`, 126 `rm ${nextCacheDir}/.ptbuild-inprogress`, 128 pushLine(`RUN --mount=type=cache,id=${dockerCacheKey},target=${nextCacheDir} ${buildCmdA.join(' && ')}`) 129 pushLine(`ENV ISNEXTBUILD=`) 134export const flatDfBuild = false 136export const dockerFileNextServ = async ({appPath, dockerEnv, lastNextBuildDf}: { 137 appPath: string, dockerEnv: Record<string, string>, lastNextBuildDf: BakedDf, 140 const {pushLine} = dockFile 143 if (withStandalone) { 145 pushLine(`FROM ${lastNextBuildDf.repo_name_tag} AS nextbuildstage`) 146 pushLine(`RUN mkdir -p ${appDir}/public`) 149 pushLine(`ENV PORT=${port}`) 150 pushLine(`ENV HOSTNAME=0.0.0.0`) 152 pushLine(`COPY --from=nextbuildstage ${appDir}/.next/standalone ${dockerApproot}`) 153 pushLine(`COPY --from=nextbuildstage ${appDir}/.next/static ${appDir}/.next/static`) 154 pushLine(`COPY --from=nextbuildstage ${appDir}/public ${appDir}/public`) 155 pushLine(`WORKDIR ${appDir}`) 156 pushLine(`EXPOSE ${port}`) 157 pushLine(`CMD ["node", "server.js"]`) 158 } else if (flatDfBuild) { 159 pushLine(lastNextBuildDf) 160 pushLine(`WORKDIR ${appDir}`) 162 pushLine(`CMD ["node", "--enable-source-maps", "runnext.mjs"]`) 164 pushLine(`FROM ${lastNextBuildDf.repo_name_tag} AS nextbuildstage`) 168 pushLine(`WORKDIR ${appDir}`) 170 pushLine(`CMD ["node", "--enable-source-maps", "runnext.mjs"]`)