fix(deploy): Next.js 배포에서 커밋된 config 가 이겨 산출물이 나오지 않던 문제 - #172
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#116 중 Next.js 부분을 고친다. 나머지 프레임워크는 이슈에 남긴다(아래 "범위" 참고).
검증 — 이슈보다 상황이 나쁘다
이슈 제목은 "자산 404" 인데, 실제로는 그 이전에 배포가 끝까지 가지 못한다. 생성 분기는 스캐폴딩 도구가 config 를 항상 만들기 때문에 현실에서 거의 발화하지 않는다.
해결 — 덮어쓰지 않고 감싼다
사용자의 config 를 지우지 않고 옆으로 옮긴 뒤, 그것을 불러와 우리가 소유하는 세 필드만 얹은 config 를 새로 쓴다.
파싱하지 않는다. Next 자신이 사용자 config 를 읽게 두고 결과 객체에만 손대므로 형식(JS/MJS/TS)이나 내용에 기대지 않는다. 사용자가 적은 redirects·env·webpack 설정은 그대로 살아남는다.
세 필드를 우리가 소유하는 근거는 각각 다르다.
output과images.unoptimized는 GitHub Pages 가 정적 호스팅이라는 사실에서,basePath는 배포 URL 에서 나온다. 셋 다 사용자가 정할 수 있는 값이 아니다.실측 (2026-08-25, 워크플로 셸 로직을 그대로 실행)
.mjs(reactStrictMode,env.MY_FLAG)output/basePath/images적용.js(images.formats), 커스텀 도메인formats유지한 채unoptimized추가,basePath: ""module.exports = () => ({...})두 가지 세부
QEPLOY_BASE_PATH를 따로 넘긴다. Next 의basePath는 trailing slash 가 없어야 하는데 기존BASE_PATH/PUBLIC_URL은 slash 를 포함한다(Vite--base, CRAhomepage가 그 형태를 요구한다). 같은 값을 재사용하면 경로가//로 겹친다.import 경로를 확장자에 따라 가른다. ESM 은 확장자를 반드시 요구하고, TypeScript 는 반대로
.ts확장자 import 를allowImportingTsExtensions없이는 허용하지 않는다.범위
Next.js 로 한정했다. CODE 프롬프트가 제시하는 넷 중 깨지는 것은 이것 하나다.
vite build --base=homepage강제 덮어쓰기create vue@latest)gatsby·sveltekit·astro·nuxt·vue-cli 는 사용자가 기존 저장소를 연결할 때만 등장한다. 같은 방식으로 덮을 수 있지만 프레임워크마다 config 형식과 필드가 달라 별도 단위로 남긴다 — #116 은 그것 때문에 열어둔다.
검증
./gradlew test전체 통과기존 저장소는 다음 배포부터 적용된다. 워크플로 파일은 배포 때마다
ensureWorkflow가 다시 쓴다.🤖 Generated with Claude Code