Skip to content

release: Next.js 배포에서 커밋된 config 가 이겨 산출물이 나오지 않던 문제 수정 - #173

Merged
dldnsgkr merged 2 commits into
mainfrom
develop
Aug 25, 2026
Merged

release: Next.js 배포에서 커밋된 config 가 이겨 산출물이 나오지 않던 문제 수정#173
dldnsgkr merged 2 commits into
mainfrom
develop

Conversation

@dldnsgkr

Copy link
Copy Markdown
Collaborator

develop → main. #172 하나뿐이고 마이그레이션 변경은 없다.

무엇을 고치나

create-next-app 은 스캐폴딩 때 next.config.mjs항상 만든다. 그런데 배포 워크플로는 config 가 없을 때만 만들고 있으면 경고만 남겼다. 그래서 생성 분기는 현실에서 거의 발화하지 않고 커밋된 config 가 유일한 진실이 된다.

그 config 에는 output: 'export' 가 없다. next build.next 만 만들고 ./out 은 생기지 않으므로 publish 스텝이 그 디렉터리를 찾다 실패한다 — 이슈 제목의 "자산 404" 이전에 배포 자체가 끝까지 가지 못한다.

해결 — 덮어쓰지 않고 감싼다

사용자의 config 를 지우지 않고 옆으로 옮긴 뒤, 그것을 불러와 우리가 소유하는 세 필드만 얹는다. 파싱하지 않으므로 형식(JS/MJS/TS)이나 내용에 기대지 않고, 사용자가 적은 redirects·env·webpack 설정은 그대로 살아남는다.

outputimages.unoptimized 는 GitHub Pages 가 정적 호스팅이라는 사실에서, basePath 는 배포 URL 에서 나온다 — 셋 다 사용자가 정할 수 있는 값이 아니다.

실측 (워크플로 셸 로직을 그대로 실행)

입력 결과
ESM .mjs (reactStrictMode, env) 유지 + 세 필드 적용
CJS .js (images.formats), 커스텀 도메인 formats 유지 + unoptimized, basePath: ""
함수형 () => ({...}) 평가해서 병합

basePath 는 trailing slash 가 없어야 해서 QEPLOY_BASE_PATH 를 따로 넘긴다(기존 BASE_PATH/PUBLIC_URL 은 slash 포함). TypeScript 는 .ts 확장자 import 를 허용하지 않아 import 경로를 확장자에 따라 가른다.

범위

Next.js 로 한정했다. CODE 프롬프트가 제시하는 넷(Vite+React, CRA, Vue, Next.js) 중 깨지는 것은 이것 하나이고, 나머지는 vite build --basehomepage 덮어쓰기로 이미 배포 시점 값이 이긴다. gatsby·sveltekit·astro·nuxt·vue-cli 는 기존 저장소 연결에서만 등장하므로 #116 을 열어둔다.

검증

  • 마이그레이션 없음. 워크플로 템플릿과 테스트만 바뀐다
  • 테스트 4개 추가, ./gradlew test 전체 통과
  • CI 통과, dev 배포 성공(bc37c6a) 및 기동 확인

기존 저장소는 다음 배포부터 적용된다 — 워크플로 파일은 배포 때마다 ensureWorkflow 가 다시 쓴다.

🤖 Generated with Claude Code

dldnsgkr and others added 2 commits August 25, 2026 19:32
config 가 없을 때만 만들고 있으면 경고만 남겼는데, create-next-app 은 스캐폴딩 때
next.config.mjs 를 항상 만든다. 그래서 생성 분기는 현실에서 거의 발화하지 않고
커밋된 config 가 유일한 진실이 된다.

그 config 에는 output: 'export' 가 없다. next build 는 .next 만 만들고 ./out 은
생기지 않으므로 publish 스텝이 그 디렉터리를 찾다 실패한다 — 자산 404 이전에 배포
자체가 끝까지 가지 못한다.

basePath 도 커밋된 값이 알 수 없는 값이다. 커스텀 도메인이 붙으면 '/', 아니면
'/{repo}' 여야 하는데 이건 배포 시점에만 정해진다.

덮어쓰지 않고 감싼다. 사용자의 config 를 옆으로 옮긴 뒤 그것을 불러와 우리가
소유하는 세 필드만 얹은 config 를 새로 쓴다. 사용자가 적은 다른 설정(redirects,
env, webpack 등)은 그대로 살아남는다. 파싱하지 않으므로 형식(JS/MJS/TS)에 기대지
않는다 — Next 자신이 읽게 두고 결과 객체에만 손댄다.

우리가 세 필드를 소유하는 근거는 각각 다르다. output 과 images.unoptimized 는
GitHub Pages 가 정적 호스팅이라는 사실에서, basePath 는 배포 URL 에서 나온다.
셋 다 사용자가 정할 수 있는 값이 아니다.

실측(2026-08-25, 워크플로 셸 로직을 그대로 실행):

  ESM(.mjs)  사용자의 reactStrictMode·env 유지 + 세 필드 적용
  CJS(.js)   images.formats 유지한 채 unoptimized 추가, 커스텀 도메인이면 basePath ''
  함수형     module.exports = () => ({...}) 도 평가해 병합

basePath 는 trailing slash 가 없어야 해서 QEPLOY_BASE_PATH 를 따로 넘긴다.
기존 BASE_PATH/PUBLIC_URL 은 slash 를 포함한다(Vite --base, CRA homepage 가 그
형태를 요구한다).

TypeScript 는 '.ts' 확장자 import 를 허용하지 않고 ESM 은 확장자를 반드시 요구하므로
import 경로를 확장자에 따라 가른다.

범위는 Next.js 로 한정했다. 우리 CODE 프롬프트가 제시하는 넷(Vite+React, CRA, Vue,
Next.js) 중 깨지는 것은 Next.js 하나다 — 나머지는 vite build --base 나 homepage
덮어쓰기로 이미 배포 시점 값이 이긴다. gatsby/sveltekit/astro/nuxt/vue-cli 는
사용자가 기존 저장소를 연결할 때만 등장하므로 별도 단위로 남긴다(#116).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix(deploy): Next.js 배포에서 커밋된 config 가 이겨 산출물이 나오지 않던 문제
@dldnsgkr
dldnsgkr merged commit d5a7263 into main Aug 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant