개발자
류준열
Next.js에서 런타임에 환경변수를 설정 할 수 있게 하는 법
런타임 환경변수가 필요했던 이유
Next와 React에서는 환경변수가 빌드타임에 주입된다. Node.js가 없는 고객사 PC에서 환경변수를 수정하려면 본사인원에게 빌드를 요청하고 파일을 메일로 주고받는 번거로움이 있었다. 하지만 런타임에서 환경변수를 설정 할 수 있게 되면, docker-compose만 수정하면 되므로 빌드 없이 어떤 환경에서든 즉시 배포가 가능해진다.
next-runtime-env 라이브러리
런타임 환경변수를 도입하기 위해 next-runtime-env 라이브러리를 사용했다.
원리
- process.env는 Node.js 환경에서는 런타임에 접근 가능하다.
- Next.js의 서버는 Node.js이다.
- 서버컴포넌트에서는 런타임에서도 process.env에 접근이 가능하다.
위 성질을 이용하여 아래와 같이 window
객체 내부에 환경변수를 등록하는 것이다.
const innerHTML = { __html: `window['__ENV'] = ${JSON.stringify(env)}`, }; return ( <Script strategy="beforeInteractive" // 페이지 로드전에 실행 nonce={nonceString} // 콘텐츠 보안을 위해 외부 스크립트를 막는 웹사이트를 개발할때 필요 dangerouslySetInnerHTML={innerHTML} /> );
특정 페이지에서 새로고침시 환경변수 못불러오는 문제
하지만, next-runtime-env를 사용했을때 특정 페이지에서는 환경변수가 undefined로 뜨는 문제가 있었다.
라우팅을 통해 이동할때는 정상작동 하는데, 새로고침 할때만 발생하는 문제인걸로 봐서 해당 페이지에서 브라우저를 렌더링 할 때 문제가 있는 것으로 보였다.
useEffect, window 객체 등등을 살폈지만 문제가 해결되지 않았고 next-runtime-env 를 까보았지만 라이브러리 코드에서도 문제점을 찾을 수 없었다.
심지어 정적렌더링을 차단하기 위해 noStore
를 이미 사용하고 있었다.
import { unstable_noStore as noStore } from 'next/cache';
import { isBrowser } from '../helpers/is-browser';
import { PUBLIC_ENV_KEY } from './constants';
/**
* Reads a safe environment variable from the browser or any environment
* variable from the server (process.env).
*
* Usage:
* ```ts
* const API_URL = env('NEXT_PUBLIC_API_URL');
* ```
*/
export function env(key: string): string | undefined {
if (isBrowser()) {
if (!key.startsWith('NEXT_PUBLIC_')) {
throw new Error(
`Environment variable '${key}' is not public and cannot be accessed in the browser.`,
);
}
return window[PUBLIC_ENV_KEY][key];
}
noStore();
return process.env[key];
}
가설 및 해결
- 정적렌더링 하는 페이지에서는 docker compose에서 주입되는 런타임 환경변수를 확인하지 못한다.
- 페이지를 동적렌더링시키면 런타임 환경변수를 확인 할 수 있다.
unstable_noStore
는 unstable 하고, 제 역할을 못한다.
위의 가설을 토대로 아래와 같이 강제 동적렌더링 시키니 환경변수가 잘 반영되었다.
export const dynamic = 'force-dynamic';
런타임 환경변수를 사용하려면 Next.js의 캐싱을 포기해야 한다.
느낀점
아래와 같은 것들은 이전에는 생각하지 못했던 것들이다.
- Node.js에서는 process.env에 접근 가능 하기 때문에 서버컴포넌트에서 런타임 환경변수에 접근 할 수 있다는 것은 생각하지 못했다.
- Next.js가 스스로 최적화를 하는 과정이 버그로 나타날 수 있다.
그리고 Next.js의 환경변수 사용 방식에 대해 개발자들의 불만이 많은 모양이다. (discussion)
그런데 Next.js의 입장도 어느정도는 이해가 간다. 페이지를 빨리 렌더링시키려면 캐싱시키는게 좋을테니..