똑같은 삽질은 2번 하지 말자

React vol.22 (NextJS에서 process.env의 요소에 동적접근하기) 본문

카테고리 없음

React vol.22 (NextJS에서 process.env의 요소에 동적접근하기)

곽빵 2024. 9. 22. 21:05

개요

이번건은 React와는 거의 관련이 없고 NextJS에서 env를 다룰때 생긴 문제에 대해 기록하고자 한다.

 

문제

process.env[변수이름]과 같이 env의 요소에 동적으로 접근하려할 때 서버사이드의 동작에서는 문제가 없지만 클라이언트 사이드에서는 접근이 안되는 현상

 

예를 들면 

const key = 'NEXT_PUBLIC_SAMPLE';

console.log(process.env.NEXT_PUBLIC_SAMPLE);
console.log(process.env['NEXT_PUBLIC_SAMPLE']);
console.log(process.env[key]);
console.log(process.env);

// Server Side Output
somevalue
somevalue
somevalue
{ ... } // object

// Client Side Output
somevalue
somevalue
undefined
{} // empty object

 

위와 같이 표시되었다.

 

원인

Next.js에서 환경변수 처리에 관련이 있는데 이는 Webpack의 DefinePlugin의 동작 방식 때문이다. 

DefinePlugin은 Webpack에서 컴파일 시간에 환경변수나 다른 값을 글로벌 상수로 삽입할 수 있게 해주는 플러그인 인데 삽입할 때의 처리를 리터럴 값의 치환을 수행하며 주로 환경 설정 값이나 조건부 코드 실행을 위해 사용된다.

new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
});

위와 같이 process.env.NODE_ENV로 적힌 코드를 보면 현재 환경의 NODE_ENV값으로 치환한다.

이 때 치환되는 값은 문자 리터럴이며, Webpack 빌드 광정에서 코드내의 process.env.NODE_ENV의 부분을 실제 환경 값으로 대체한다.

 

위와 같은 방식이기 떄문에 동적 환경변수의 접근을 할때는 process.env.NODE_ENV와 같이 명시적으로 적힌 코드는 빌드 타임에서 치환을 수행하지만 process.env[key]와 같은 코드는 key가 빌드 타임에서 어떤 값인지 해석할 수 없기 때문에 치환을 하지 못한다.

 

이떄까지의 webpack.DefinePlugin으로 환경변수를 치환하는 작업은 물론 클라이언트 사이드에서 일어나는 것이며 서버 사이드에서는 NodeJS의 process.env 오브젝트에 접근할 수 있기 때문에 이와 같은 치환작업은 필요없으며 process.env에의 동적 접근도 물로 가능하다.

 

해결

const dynamicEnvs = require(`./dynamicEnvs/${process.env.APP_ENV || 'local'}.json`);

/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...생략
  webpack: (config, { webpack, isServer }) => {
    // For ServerSide
    Object.keys(dynamicEnvs).forEach(key => {
      process.env[key] = dynamicEnvs[key];
    });

    // For ClientSide
    if (!isServer) {
      config.plugins.push(
        new webpack.DefinePlugin({
          'process.env': JSON.stringify(dynamicEnvs),
        }),
      );
    }

    return config;
  },
};

module.exports = nextConfig;
  • APP_ENV는 각각의 .env, .env.staging, env.production등에 설정된 값으로 환경에 따라 각각 local, stg, prod의 값으로 되어 있다.
  • dynamicEnvs의 디렉터리 안에는 동적으로 접근 가능하게 설정하고 싶은 환경변수들이 환경에 따라 환경.json과 같은 파일들이 들어있다.
  • nextConfig에서 지원하는 웹팩확장기능을 통해 server, client 양쪽에서 동적환경변수에 접근할 수 있게 한다.

결론

이렇게 하면 이중으로 환경변수를 관리해야 하며 dynamicEnvs에 정의한 민감한 정보들이 클라이언트쪽에서 접근이 가능하게 되므로 보안상으로 위험이 될 수 있다. 어쩔수 없는 상황이 아니라면 동적으로 환경변수에 접근해야 하는 방법 자체를 그만두고 다른 방법을 모색하는게 더 좋은 pratice가 될 수 있을꺼 같다.

 

 

밑은 webpack.DefinePlugin의 동작부분

https://github.com/vercel/next.js/blob/384953b35c5e9935bb4a2fcdfe5056efb73cd740/packages/next/build/webpack-config.ts#L1298-L1307

 

next.js/packages/next/build/webpack-config.ts at 384953b35c5e9935bb4a2fcdfe5056efb73cd740 · vercel/next.js

The React Framework. Contribute to vercel/next.js development by creating an account on GitHub.

github.com

 

Comments