본문 바로가기
카테고리 없음

Shim에서 조건부 로딩, 모듈화, 성능 영향 최소화

by 디디이 2025. 7. 6.

기능을 흉내 내어 동작하게 만드는 Shim 코드

Shim은 자바스크립트 실행 환경이 특정 기능이나 API를 기본적으로 지원하지 않을 때, 그 기능을 흉내 내어 동작하게 만드는 코드입니다. 주로 레거시 브라우저나 오래된 Node.js 런타임에서 최신 웹 표준을 에뮬레이션할 때 사용됩니다. 하지만 Shim은 잘못 설계될 경우 성능 저하, 충돌, 유지보수 어려움이 발생할 수 있기 때문에 최적화가 필수입니다. 이 글에서는 실무에서 유용한 Shim 코드 최적화 기법을 정리합니다.

조건부 로딩과 존재 여부 검사

Shim의 핵심 목적은 ‘없는 기능을 대신 제공’하는 것이므로, **기능이 이미 있는 경우에는 건드리지 않아야** 합니다. 이를 위해 가장 기본적인 패턴이 바로 "존재 여부 검사"입니다:

if (!window.Promise) {
  // Promise Shim을 로드하거나 구현
}

Shim을 작성할 때는 항상 **기능 탐지(Feature Detection)**를 먼저 수행해야 하며, 이를 위해 Modernizr 같은 도구를 사용할 수도 있습니다. 조건부 로딩은 성능을 향상시킬 뿐 아니라, 최신 브라우저에서 Shim 코드가 오히려 기능을 덮어쓰는 문제를 방지해줍니다.

또한 동적으로 Shim을 로드하는 방식도 고려할 수 있습니다. 예:

if (!window.fetch) {
  import('./shim/fetch.js').then(() => {
    console.log('Fetch Shim 로드됨');
  });
}

이 방식은 초기 로딩 속도에 부담을 주지 않고, 필요한 시점에만 Shim을 불러올 수 있어 성능적인 이점이 있습니다.

최소 범위 오염 및 모듈화

Shim은 글로벌 객체나 기본 프로토타입을 수정하게 되므로, 자칫하면 다른 코드와 충돌하거나 예기치 않은 부작용을 초래할 수 있습니다. 이를 방지하기 위한 가장 중요한 전략은 **모듈화와 네임스페이스 분리**입니다.

예를 들어, 직접 전역 객체를 수정하기보다는 Shim 함수를 별도로 정의하고 선택적으로 사용할 수 있도록 만듭니다:

function defineCustomBind(obj) {
  if (!obj.bind) {
    obj.bind = function(fn) {
      // 사용자 정의 bind 구현
    };
  }
}
defineCustomBind(Function.prototype);

또는 모듈 번들링 도구(Webpack, Rollup)를 활용해 필요한 Shim만 포함하도록 구성할 수 있습니다. 다음은 예시 Webpack 설정입니다:

// webpack.config.js
module.exports = {
  entry: {
    main: './index.js',
    shim: './shims/es5.js',
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

이렇게 Shim을 별도의 번들로 분리하면, 필요할 때만 로드되므로 전체 파일 크기를 줄이고 유지보수도 용이합니다. 또한 외부 라이브러리 Shim(ex: es5-shim, core-js)은 필요한 기능만 가져오도록 tree-shaking이나 커스텀 빌드가 가능하도록 구성하는 것이 바람직합니다.

성능 영향 최소화와 테스트 전략

Shim은 런타임에서 기본 API의 대체 역할을 하므로, 성능에 영향을 줄 수 있습니다. 특히 반복 호출되는 메서드나 루프 안에 있는 코드에 Shim이 개입되면 병목이 발생할 수 있습니다. 이를 방지하기 위한 전략은 다음과 같습니다:

  • 최소 구현: 표준 사양의 모든 기능을 구현하기보다는 실제 사용하는 범위만 구현
  • 함수 캐싱: 자주 호출되는 내부 함수는 캐싱하여 중복 연산 최소화
  • 실행 전 검사: 초기화 시점에만 조건 검사하고, 이후는 빠르게 실행

예를 들어, 배열의 includes Shim을 구현할 때 다음과 같이 작성할 수 있습니다:

if (!Array.prototype.includes) {
  Array.prototype.includes = function(value) {
    return this.indexOf(value) !== -1;
  };
}

또한 **Shim 코드의 테스트는 일반 유닛 테스트 외에도 호환성 테스트가 필수**입니다. 대표적인 전략은 다음과 같습니다:

  • IE11, Edge Legacy, Android WebView 등 실제 레거시 환경 테스트
  • Jest, Mocha 등으로 Shim 함수 유닛 테스트 작성
  • 라이브 환경 Shim 적용 여부를 자동 확인하는 기능 포함

CI/CD 파이프라인에 브라우저 테스트 환경을 포함시키면, Shim 코드 변경 시 호환성 이슈를 조기에 발견할 수 있어 안정성을 크게 높일 수 있습니다.

Shim은 레거시 브라우저나 미지원 환경에서도 최신 웹 기능을 구현할 수 있게 해주는 유용한 도구입니다. 하지만 무분별한 사용은 코드 중복, 충돌, 성능 저하로 이어질 수 있으므로, 조건부 로딩, 네임스페이스 분리, 성능 고려, 자동화된 테스트 등을 통해 철저하게 최적화하는 것이 중요합니다.