[Vite] 빌드 시 콘솔 로그 제거하기

프론트엔드 개발에서 console.log는 디버깅의 필수 도구지만 프로덕션 환경에서는 보안 위험과 성능 저하를 가져올 수 있다.

이번 글에서는 Vite를 사용하는 프로젝트에서 빌드 시 콘솔 로그를 효과적으로 제거하는 방법을 살펴보자.

기본 설정: 모든 콘솔 로그 제거하기

Vite에서는 Terser라는 JavaScript 압축 도구를 사용하여 콘솔 로그를 제거할 수 있다.

아래는 vite.config.js에 추가할 수 있는 기본 설정이다:

export default {
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,  // 모든 console.* 호출 제거
        drop_debugger: true  // 모든 debugger 문 제거
      }
    }
  }
}

이 설정을 사용하려면 먼저 Terser를 설치해야 한다:

pnpm add -D terser
# 또는
npm install --save-dev terser

로깅 레벨 분리: 선택적으로 콘솔 로그 제거하기

모든 콘솔 로그를 제거하는 것이 항상 최선은 아니다.

특히 console.errorconsole.warn과 같은 중요한 로그는 프로덕션 환경에서도 유지하고 싶을 수 있다.

Terser를 사용하면 특정 타입의 콘솔 로그만 선택적으로 제거할 수 있다.

export default {
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        // 특정 유형의 콘솔 로그만 제거
        pure_funcs: [
          'console.log',
          'console.info',
          'console.debug',
          'console.trace'
        ]
      }
    }
  }
}

위 설정은 console.log, console.info, console.debug, console.trace는 제거하지만 console.warnconsole.error는 유지한다.

이렇게 하면 개발자가 의도적으로 남겨둔 중요한 경고나 오류 메시지는 프로덕션 환경에서도 표시된다.

로깅 레벨 분리의 장점

  1. 중요 오류 메시지 유지: 사용자 경험에 영향을 미치는 중요한 오류는 프로덕션에서도 로깅할 수 있다.
  2. 디버깅 용이성: 실제 프로덕션 이슈 발생 시 console.error를 통해 남긴 로그가 문제 해결에 도움이 될 수 있다.
  3. 보안과 성능의 균형: 불필요한 디버깅 로그는 제거하면서도 필요한 정보는 유지할 수 있다.

실제 사용 사례

아래는 개발 환경에서 어떻게 다양한 로깅 레벨을 사용하고, 프로덕션에서는 어떻게 처리되는지 보여주는 예시다:

// 개발 코드
function processUserData(userData) {
  console.log('Processing user data:', userData);  // 디버깅용 로그 (프로덕션에서 제거됨)

  if (!userData.email) {
    console.warn('User has no email address');     // 경고 로그 (프로덕션에서 유지됨)
    return false;
  }

  try {
    // 데이터 처리 로직
    return processedData;
  } catch (error) {
    console.error('Failed to process user data:', error);  // 오류 로그 (프로덕션에서 유지됨)
    return null;
  }
}

위 코드에서 설정한 로깅 레벨 분리 옵션을 적용하면, 프로덕션 빌드 후에는 console.log만 제거되고 console.warnconsole.error는 유지된다.

선별적 로깅을 위한 추가 패턴

특정 중요 로그를 프로덕션에서도 유지하고 싶다면 다음과 같은 패턴을 사용할 수도 있다:

// 커스텀 로거 함수
const logger = {
  debug: (message, ...args) => {
    console.log(`[DEBUG] ${message}`, ...args);
  },

  info: (message, ...args) => {
    console.log(`[INFO] ${message}`, ...args);
  },

  // 프로덕션에서도 유지하고 싶은 중요 로그
  important: (message, ...args) => {
    console.error(`[IMPORTANT] ${message}`, ...args);  // console.error 사용
  }
};

// 사용 예
logger.debug('일반 디버깅 메시지');  // 프로덕션에서 제거됨
logger.important('중요한 비즈니스 이벤트 발생'); // 프로덕션에서 유지됨 (console.error 사용)

이렇게 하면 console.log는 모두 제거되지만, console.error로 남긴 중요 로그는 프로덕션에서도 확인할 수 있다.

주의사항

  1. 프로덕션 로그에 민감한 정보가 포함되지 않도록 주의해야 한다.
  2. 과도한 로깅은 여전히 성능에 영향을 줄 수 있으므로 꼭 필요한 로그만 유지하는 것이 좋다.
  3. 로깅 레벨 분리 옵션은 코드 압축 과정에서 적용되므로 빌드된 코드의 크기와 실행 성능에도 영향을 미친다.

로깅 레벨을 적절히 분리하여 관리하면, 디버깅의 용이성과 프로덕션 환경의 보안 및 성능 요구사항 사이에서 좋은 균형을 찾을 수 있다.