[JS] ECMAScript Modules: 왜 TC39는 새로운 모듈 시스템을 설계했을까?

soleil_lucy·2025년 5월 25일
1
post-thumbnail

ECMAScript Modules(ESM)이 궁금해진 이유?

최근에 작성한 디스코드 봇 개발 후기에서, 왜 CommonJS를 사용했는지에 대한 질문을 받았습니다. 저는 당시 공식 문서에 나온 예제가 CommonJS 방식이었기 때문에 이를 선택했다고 설명했지만, 이 답변이 충분하지 않다는 것을 느꼈습니다.

나아가, 코드 리팩토링 시 ECMAScript Modules(ESM)으로 전환할 계획이라고 밝히면서도, 왜 ESM을 선택하는 것이 좋은지 명확히 설명하지 못했습니다. 이에 따라, ESM에 대해 더 깊이 이해하고 싶어졌습니다.

추가로 CommonJS와 ESM에 대해서 다시 알아보다가 TC39는 기존에 모듈 시스템이 있음에도 불구하고 새롭게 만들어낸 이유가 뭔지 궁금해져 알아본 내용을 통해 이 글을 작성하게 됐습니다.

CommonJS?
Node.js 환경에서 모듈화를 위해 만들어진 시스템

ESM, ECMAScript Modules?
자바스크립트의 공식 표준 모듈 시스템으로 브라우저와 Node.js에서 모두 사용할 수 있어, 일관된 모듈 사용을 지원함

CommonJS와 ESM의 차이가 궁금하신 분들은 작년에 제가 쓴 글이 도움이 될까 싶어 첨부해둡니다. [JS] CommonJS와 ECMAScript Modules란?

ESM의 탄생 배경

이전의 모듈 시스템의 한계

ESM이 표준화되기 전, JavaScript에는 공식적인 모듈 시스템이 없었습니다. 개발자들은 ComonJS(Node.js 환경), AMD(브라우저 환경), UMD 등 다양한 비표준 모듈 시스템을 사용해야 했습니다. 이들 시스템은 다음과 같은 문제점을 갖고 있었습니다:

  • 상호 호환성 부족: 각 환경마다 모듈 시스템이 달라 코드의 재사용성과 호환성이 떨어짐.
  • 런타임/빌드타임 차이: CommonJS는 런타임에 동적으로, require를 실행하고, AMD(Asynchronous Module Definition)는 비동기 로딩을 지원하지만 복잡함.
  • 정적 분석 불가: 기존 시스템은 정적 분석이 어려워, 트리 쉐이킹(tree-shaking) 같은 최적화가 힘듦.
  • 브라우저 네이티브 지원 부재: 브라우저에서 바로 사용할 수 없고, 번들러(webpack, Rollup 등)나 트랜스파일러(Bable 등)의 지원이 필수임.

AMD, Asynchronous Module Definition?
AMD는 자바스크립트에서 모듈과 그 의존성을 정의하고, 필요한 모듈을 비동기적으로(즉, 동시에 여러 개를) 로드할 수 있게 해주는 표준 방식.

트리 쉐이킹?
사용하지 않는(dead code) 코드를 번들 파일에서 제거하는 최적화 기법. 실제로 쓰이는 코드만 남기고 나머지는 빌드 결과물에서 떨어내서, 파일 크기를 줄이고 로딩 속도를 빠르게 해줌

번들러?
여러 개의 자바스크립트, CSS, HTML 파일 등 프로젝트의 지원들을 하나 또는 소수의 파일로 합쳐주는 도구.

트랜스파일러?
한 프로그래밍 언어의 코드를 다른 언어나 다른 버전의 코드로 변환해주는 도구. 예를 들어, 최신 자바스크립트(ES6+) 코드를 구형 브라우저에서도 동작하는 ES5 코드로 바꿔주는 Babel이 대표적인 트랜스파일러.

브라우저 네이티브?
웹 브라우저(크롬, 사파리 등)가 어떤 기능을 별도의 설치나 추가 도구 없이 기본적으로 바로 지원한다는 뜻

표준 모듈 시스템의 필요성

ECMA International Logo

TC39(ECMAScript 표준화 위원회)는 위와 같은 문제를 해결하고자, 다음과 같은 목표로 ESM을 설계했습니다:

TC39(ECMAScript 표준화 위원회)?
자바스크립트(ECMAScript) 언어의 공식 규칙과 새로운 기능을 정하고 관리하는 국제 표준화 단체. 구글, 마이크로소프트, 모질라, 애플 등 주요 IT 기업의 전문가들이 모여서, 자바스크립트가 어떻게 발전할지 논의하고 결정함.

  • 정적 구조: import/export 구문은 정적으로 분석 가능해, 빌드 도구가 의존성 그래프를 쉽게 파악하고 코드 최적화(트리 쉐이킹 등)가 가능함.
  • 브라우저와 서버 모두 지원: 하나의 표준 문법으로 브라우저와 Node.js 등 다양한 환경에서 동일하게 동작함.
  • 명확한 스코프와 캡슐화: 모듈은 자체 스코프를 가지며, 글로벌 오염을 막음. 모듈 내 변수는 외부에서 접근할 수 없고, 명시적으로 export/import 해야만 공유됨.
  • 네이티브 브라우저 지원: <script type="module">로 브라우저에서 바로 모듈을 로드할 수 있음. 별도의 번들러 없이도 모듈 시스템을 활용할 수 있음.
  • 성능과 보안: 모듈은 한 번만 평가되고, CORS 정책 등 보안이 강화된 방식으로 로드됨.

ESM의 주요 특징

  • 정적 import/export: 의존성 분석, 트리 쉐이킹, 최적화에 유리
  • 동적 import(): 필요할 때 모듈을 비동기로 로드 가능(코드 스플리팅)
  • 엄격 모드 기본 적용: 모듈은 항상 strict mode로 실행
  • 모듈 스코프: 글로벌 오염 방지, this는 undefined
  • 브라우저와 Node.js에서 공식 지원: .mjs 확장자 권장, <script type="module"> 지원

결론

TC39가 ECMAScript Modules를 만든 이유는, JavaScript 생태계의 파편화된 모듈 시스템을 표준화하고, 정적 분석과 최적화, 브라우저/서버 양쪽에서의 일관된 동작, 보안 및 성능 향상을 실현하기 위함입니다.

도입부에 언급한 질문에 대해 다시 답변하자면

Q. 디스코드 봇을 만들 때, CommonJS를 채택한 이유?

디스코드 봇 개발 당시, Discord.js 라이브러리의 공식 문서에서 CommonJS 예제를 제공했기 때문에 이를 선택했습니다. 이 방식은 빠르게 봇을 구현하는 데 유용했습니다.

Q. 리팩토링 계획에 ESM으로 마이그레이션 하려는 이유?

이후에는 표준화된 모듈 시스템인 ESM으로 전환하는 것이 더 낫다고 판단했습니다. ESM은 브라우저와 Node.js 모두에서 일관된 모듈 사용을 가능하게 하고, 최신 기술 표준을 준수하여 코드의 유지 보수성과 확장성을 높일 수 있기 때문입니다.

한 줄 요약

TC39는 JavaScript의 파편화된 모듈 시스템을 통합하고 최적화하여 다양한 환경에서 일관성과 성능을 향상시키기 위해 ECMAScript Modules(ESM)을 설계했습니다.

참고 자료

profile
여행과 책을 좋아하는 개발자입니다.

0개의 댓글