NHJ.log

React Router v7 Pre-render + Netlify 호환 이슈 해결 과정

(수정: 2026년 2월 16일)
React Router v7NetlifyViteOpen SourceSSG

TL;DR


💡
  1. React Router v7의 prerender 기능이 Netlify 환경에서 "Server build file not found" 에러로 실패

  2. 원인: Netlify 플러그인이 rollupOptions.input을 덮어써서 server-build가 manifest에서 제외됨

  3. 해결: enforce: 'post' 플러그인으로 우회 후, Netlify 플러그인에 PR 기여 → v2.1.3에 반영됨

배경: Pre-rendering(SSG)란?


빌드 시점에 특정 라우트를 미리 HTML로 생성해두는 것.

요청 → 이미 생성된 HTML 반환 (SSR 불필요, CDN에서 바로 서빙)

문제 분석


React Router의 prerender는 단순한 케이스를 위해 설계됨:

[일반적인 구조]
vite build → server-build 생성 → prerender가 server-build 로드 → HTML 생성

하지만 커스텀 서버 (Vercel Functions, Netlify Functions 등)를 쓰면:

[커스텀 서버 구조]
vite build → server-build 생성
           → custom server entry 생성
 
prerender는 server-build만 로드 → custom server entry 무시됨!

이로 인해 React Router v7의 prerender 기능이 Netlify, Cloudflare, Vercel 등 3rd party 서버리스 플랫폼 플러그인과 호환되지 않음.

증상

[react-router] Server build file not found in manifest

원인

플랫폼 플러그인들이 서버 빌드 출력을 수정하여 React Router의 prerender 프로세스가 manifest에서 서버 빌드 파일을 찾지 못함.

Netlify 플러그인의 경우:

@netlify/vite-plugin-react-routerconfig 훅에서 rollupOptions.input덮어쓰기함:

// node_modules/@netlify/vite-plugin-react-router/dist/index.js
config.build.rollupOptions.input = {
  server: "virtual:netlify-server"
};

이로 인해 virtual:react-router/server-build가 manifest에서 제외됨.

해결 과정


시도 1: 기존 Workaround (실패)

https://github.com/remix-run/react-router/issues/13226 에서 제시된 workaround:

export default defineConfig(({ isSsrBuild }) => ({
  build: {
    rollupOptions: isSsrBuild
      ? { input: ['virtual:react-router/server-build'] }
      : undefined,
  },
}));

Netlify 환경에서는 플러그인이 이 설정을 덮어쓰기 때문에 동일한 에러 발생.

시도 2: enforce: 'post' 플러그인 (성공)

⚠️ v2.1.3 이후로는 이 workaround가 필요 없음

enforce: 'post'를 사용해 Netlify 플러그인 이후에 server-build를 input에 추가:

// vite.config.ts
import { reactRouter } from '@react-router/dev/vite';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import netlifyReactRouter from '@netlify/vite-plugin-react-router';
import netlify from '@netlify/vite-plugin';
 
export default defineConfig({
  plugins: [
    reactRouter(),
    tsconfigPaths(),
    netlifyReactRouter(),
    netlify(),
 
    // Prerender fix: server-build를 rollup input에 추가
    {
      name: 'add-server-build-to-input',
      enforce: 'post',
      config(config, { command, isSsrBuild }) {
        if (isSsrBuild && command === 'build') {
          const currentInput = config.build?.rollupOptions?.input;
          if (currentInput && typeof currentInput === 'object') {
            return {
              build: {
                rollupOptions: {
                  input: {
                    ...currentInput,
                    'server-build': 'virtual:react-router/server-build',
                  },
                },
              },
            };
          }
        }
      },
    },
  ],
});
결과:
build/server/server.js                         0.35 kB
build/server/assets/server-build-lv_U4l46.js  14.57 kB  ← 추가됨!
 
Prerender (html): / -> build/client/index.html
✓ built in 292ms

시도 3: 근본 해결 - PR 기여

근본적인 해결을 위해 @netlify/vite-plugin-react-router에 PR 제출:

플러그인이 기존 input을 덮어쓰지 않고 병합하도록 수정:

// Before (문제)
config.build.rollupOptions.input = {
  server: "virtual:netlify-server"
};
 
// After (수정)
const existingInput = config.build?.rollupOptions?.input;
// ... 기존 input 형태에 따라 병합 처리
config.build.rollupOptions.input = {
  ...mergedInput,
  server: "virtual:netlify-server",
};
 

향후 React Router 팀에서 Vite Preview Server 방식으로 공식 지원 예정 (RFC #14651)

후속 진행

PR #607은 GitHub Actions 워크플로우 권한 문제로 인해 외부 기여자가 직접 CI를 실행할 수 없어 닫혔다.
하지만 메인테이너(Philippe Serhal)가 PR #620을 새로 생성하면서:

  • 내 커밋을 체리픽하여 포함

  • 코드를 더 견고하게 개선 (rollup input 병합 로직 분리, 테스트 커버리지 추가)

  • PR 본문에 "Inspired by #606 (thank you @nahyeongjin1!)" 언급

2026년 1월 19일, PR #620이 머지되었다! 🎉

이제 workaround 없이 깔끔한 설정으로 prerender가 동작한다:

관련 자료


이슈 & PR

링크설명
#13226Cloudflare Workers 동일 이슈
#14096Netlify 이슈 (closed as not planned)
Discussion #14651Vite Preview Server RFC
PR #14650Preview Server 구현 (리뷰 대기)
Netlify #606Netlify 플러그인 이슈
Netlify #607Netlify 플러그인 수정 PR
Netlify #620Netlify 플러그인 수정 PR (머지됨 ✅)

Comments