Skip to content

Migrate apps/front, apps/admin from Next.js to vinext - #9

Merged
owjs3901 merged 4 commits into
mainfrom
owjs3901/migrate-vinext
Aug 30, 2026
Merged

Migrate apps/front, apps/admin from Next.js to vinext#9
owjs3901 merged 4 commits into
mainfrom
owjs3901/migrate-vinext

Conversation

@owjs3901

Copy link
Copy Markdown
Contributor

배경

빠른 개발 속도 및 프로덕션 빌드 용량 절감을 위해 Next.js -> vinext(cloudflare/vinext, Vite 기반 Next.js API 재구현체) 완전 전환.

devfive-center(origin/main), yeollin-cms 등 조직 내 다른 저장소의 검증된 패턴을 그대로 적용:

  • \�ite.config.ts: [devupApi(), DevupUI({ include: [...] }), vinext({ nextConfig: { output: 'standalone' } })]\ — nitro 사용 안 함 (Cloudflare Workers 배포 대상 아니므로 불필요, 오히려 nitro를 물렸을 때 admin 프로덕션에서 \SyntaxError: Export 'ssr_exports' is not defined\가 재현됨을 직접 확인함)
  • vinext 자체가 \dist/standalone/server.js\를 생성 — 기존 .next/standalone/server.js\와 동일한 진입점 파일명이라 \ecosystem.json(pm2) 변경 불필요
  • \RSC assets manifest emits modulepreload URLs for JS chunks that are never built (CSS-only chunks) cloudflare/vinext#3064(devup-ui가 CSS를 별도 청크로 분리할 때 RSC asset manifest가 존재하지 않는 js 참조를 남겨 페이지당 수십 건의 404 발생) 대응용 \scripts/prune-missing-assets.ts\ 추가 (devfive-center에서 이미 검증된 워크어라운드)

변경 사항

  • \�pps/front, \�pps/admin:
    ext, @devup-ui/next-plugin, @devup-api/next-plugin\ 제거. \�inext, \�ite, @vitejs/plugin-rsc,
    eact-server-dom-webpack, @devup-ui/vite-plugin, @devup-api/vite-plugin\ 추가

  • ext.config.ts\ 삭제, \�ite.config.ts\ 추가
  • \dev/\�uild/\start\ 스크립트가 이제 \�inext dev/\�inext build/\�inext start\
  • \Dockerfile.build: .next/standalone\ 경로 대신 \dist/standalone\ 복사로 단순화 (FRONT_RUNTIME 분기 없이 vinext 단일 경로)
  • \Dockerfile.front, \ecosystem.json, .github/workflows/deploy.yml: 변경 불필요 (검증 완료)

검증

  • \�un run -F ./apps/admin build\ / \�un run -F ./apps/front build: 통과, \dist/standalone/\ 생성 확인
  • admin \dist/standalone/server.js\를 직접
    ode\로 띄워 실제 curl 검증:
    • /signin\ → 200
    • /dashboard\ → 200 (client 컴포넌트 + react-query 있는 페이지 — nitro 없이 정상 동작 재확인)
  • front \dist/standalone/server.js\ → /\ → 200
  • devup-ui CSS 정상 적용 확인 (Playwright로 실제 렌더된 클래스명/computed style 확인)
  • \�un run lint: 통과 (exit 0)
  • \�un test: 8 passed, 0 failed
  • \�pps/front/src/api.ts\의 기존(무관) 타입 에러는 vinext build가 별도 blocking typecheck를 돌리지 않아 더 이상 빌드를 막지 않음 (애플리케이션 로직은 건드리지 않음, 필요 시 별도로 수정 권장)

알려진 리스크

Base 브랜치 안내

이 PR은 아직 머지되지 않은 #8(디펜던시 업데이트) 위에 쌓은 것이라 base를 \owjs3901/update-dep\로 설정함. #8이 머지되면 base를 \main\으로 재지정 예정.

@owjs3901

Copy link
Copy Markdown
Contributor Author

재검증 완료 ✅

devup-ui \ ix-css-chunk-reemit\ 워크트리에서 요청한 CSS 중복 emit 수정이 PR #653로 머지되어 @devup-ui/vite-plugin@1.0.69\로 배포됨.

\�unx @dependency-check-updates/cli -d -u --rm\로 재실행 후 전체 재검증:

  • @devup-ui/vite-plugin\ 1.0.68 → 1.0.69 업데이트 후 admin 빌드에서 [FILE_NAME_CONFLICT]\ 경고가 완전히 사라짐 확인
  • \�espera\ 0.3.1 → 0.4.0 (Rust API build-dependency) — \cargo check/\clippy/\ mt\ 전부 통과
  • \ ypescript ^7\은 여전히 typescript-eslint 미지원이라 ^6\ pin 유지
  • \�un run lint: 통과, \�un test: 8 passed
  • admin \dist/standalone/server.js\ 재기동 후 /signin(200), /dashboard(200) 재확인 — 정상

이제 알려진 리스크였던 CSS 파일명 충돌 경고까지 해소됨.

Base automatically changed from owjs3901/update-dep to main August 30, 2026 13:05
vinext#3064 (phantom .js modulepreload refs for CSS-only chunks) is a
known, harmless upstream bug - confirmed non-blocking for rendering,
hydration, and interaction. Not worth carrying a bespoke build-output
post-processing script for a cosmetic 404 issue.
@owjs3901

Copy link
Copy Markdown
Contributor Author

scripts/prune-missing-assets.ts 제거

별도 후처리 스크립트를 빌드 파이프라인에 넣는 것 자체가 유지보수 부담(까먹기 쉬움, Docker COPY 스텝 추가 등)이라 판단해 제거함.

근본 원인: cloudflare/vinext#3064 — devup-ui처럼 CSS를 전용 청크로 분리하는 플러그인을 쓰면 vinext의 RSC asset manifest가 실재하지 않는 .js\ 청크 URL을 남겨 \modulepreload\ 요청이 404남. vinext 자체의 아직 안 고쳐진 버그이며, 우리 쪽 vite.config로 우회 불가능(원인이 vinext 내부 manifest 생성 로직 + standalone 번들 조립 단계에 있어 Vite 플러그인 훅 생명주기 밖에서 발생).

왜 그냥 두기로 했는지: 위 이슈에 명시된 대로 \modulepreload\는 힌트일 뿐이라 렌더링/hydration/인터랙션에 영향 없음(우리도 admin /signin, /dashboard\ 실제 curl + 이전 Playwright 검증으로 확인함). 페이지당 낭비되는 요청 수만 늘어나는 정도라, 이 정도 코스메틱 이슈 때문에 자체 빌드 후처리 스크립트를 계속 들고가는 것보다는 vinext가 upstream에서 고칠 때까지 그냥 두는 게 낫다고 판단.

변경 사항

  • \scripts/prune-missing-assets.ts, \scripts/prune-missing-assets.test.ts\ 삭제
  • \�pps/front, \�pps/admin\의 \�uild\ 스크립트를 \�inext build && bun run ../../scripts/prune-missing-assets.ts dist\ → \�inext build\로 단순화
  • \Dockerfile.build\에서 \COPY scripts ./scripts\ 제거

검증

  • \�un run build(front+admin): 통과
  • admin \dist/standalone/server.js\ 재기동 → /signin(200), /dashboard(200) 재확인
  • \�un run lint: 통과, \�un test: 3 passed (스크립트 테스트 삭제로 8→3)

@devup-ui/plugin-utils' createNodeModulesExcludeRegex already
hardcodes the entire @devup-ui scope, so include: ['@devup-ui/reset-css',
'@devup-ui/components'] was a no-op. Verified: identical module counts
and byte-identical rendered HTML before/after.
@owjs3901

Copy link
Copy Markdown
Contributor Author

DevupUI({ include: [...] }) 옵션 제거

devup-ui-plugin-utils의 \createNodeModulesExcludeRegex(include, extra)\를 직접 확인:

\\js
function Ot(include, extra) {
let e =
ode_modules(?!.*()(...))
return new RegExp(...)
}
\\

@devup-ui, @devup-editor\ 스코프 전체가 이미 하드코딩으로 항상 node_modules 제외 대상에서 빠져있음(=항상 스캔 대상). \ssr.noExternal\도 /@devup-ui/\ 정규식으로 스코프 전체가 이미 하드코딩됨. 즉 \include: ['@devup-ui/reset-css', '@devup-ui/components']\는 둘 다 @devup-ui/\ 스코프라 완전히 dead config였음.

검증: 옵션 제거 전/후 빌드에서 transform된 모듈 수 완전 동일(front 129/230/81, admin 298/258/290/269/252), 렌더된 HTML 바이트 수도 완전 동일(front 8542, admin/signin 12606) — 실측으로 무변화 확인.

@owjs3901
owjs3901 merged commit ba76dc1 into main Aug 30, 2026
@owjs3901
owjs3901 deleted the owjs3901/migrate-vinext branch August 30, 2026 13:18
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