IT 엘도라도 로고
IT 엘도라도
황금

JavaScript 모듈 내보내기/불러오기 (CommonJS vs ES6)

2020-08-25 15:53

JavaScript 모듈 내보내기/불러오기 (CommonJS vs ES6)

1. JavaScript 모듈 시스템

파일 단위의 모듈화는 코드의 재활용성을 극대화시킴으로써 애플리케이션 개발의 생산성을 엄청나게 향상시킨다. 그런데 초창기 JavaScript는 모듈 시스템이라는 것을 갖추고 있지 않았다. 그나마 가지고 있는 것이라고는 <script> 태그를 통해 또 다른 JavaScript 소스 파일들을 서버에게 요청하는 방식이었는데, 각각의 <script> 태그에 의해 로드된 JavaScript 코드들은 사실상 하나의 파일 안에 작성된 것처럼 동작했다. 즉, 로드된 각 JavaSript 소스 파일마다 독립적인 파일 스코프를 가지고 있는 것이 아니라 하나의 전역 객체를 공유하는 방식이었던 것이다. 이로 인해 서로 다른 JavaScript 소스 파일에 존재하는 변수나 함수들이 같은 이름을 가짐으로써 충돌하는 문제들이 발생하기 매우 쉬웠다. 즉 모듈 시스템이란 것이 사실상 없었던 것이다.
이러한 배경에서 JavaScript를 클라이언트 사이드에서뿐 아니라 서버 사이드에서도 범용적으로 사용하기 위한 움직임까지 일어나면서, 모듈화는 JavaScript가 풀어야 할 핵심 과제가 되어 버렸다. 그래서 등장한 것이 바로 CommonJSAMD(Asynchronous Module Definition)였다. 결국 JavaScript의 모듈화 방식은 크게 CommonJS와 AMD로 나뉘게 되었다.
이때 서버 사이드 JavaScript 런타임인 Node.js의 경우 모듈 시스템으로서 CommonJS를 채택하였다. 따라서 Node.js 환경에서는 모듈별로 독립적인 파일 스코프를 가진다는 것을 유추할 수 있다. 그리고 이와 같은 방식으로 브라우저에서 JavaScript를 모듈화 하기 위해서는 CommonJS 혹은 AMD를 기반으로 구현된 별도의 모듈 로더 라이브러리를 사용해야 했다. 이러한 상황에서, ES6부터는 브라우저 단에서도 쉽게 JavaScript의 모듈화가 가능하도록 모듈 시스템이 추가되었다. 따라서 오늘날 많은 브라우저들은 ES6 기반의 모듈 내보내기 및 불러오기 방식을 지원하고 있다.
💡
이번 포스팅에서는 CommonJS 기반의 모듈 시스템과 ES6 기반의 모듈 시스템에 대해서만 알아볼 것이다.
 

2. CommonJS 기반의 모듈 내보내기 및 불러오기 (module.exports, require)

2-1. 개요

앞서 배경 설명에서 언급했듯이, Node.js 환경에서 실행되는 JavaScript는 모듈 시스템으로서 CommonJS 방식을 지원한다. 이 방식에서는 module.exports 객체를 이용하여 자신의 데이터를 외부로 내보낼 수 있고, require() 함수를 이용하여 외부 모듈의 데이터를 불러올 수 있다. 만약 Babel 등의 컴파일러를 사용한다면 뒤에서 설명할 ES6 기반의 모듈 내보내기 및 불러오기 방식을 사용해도 알아서 module.exports 객체 및 require() 함수 기반의 방식으로 변환될 것이다.

2-2. 모듈 내보내기 (module.exports)

자신의 데이터를 외부로 내보내려면 module.exports 변수에 내보내고자 하는 데이터들을 담은 객체를 지정해주면 된다. 그러면 이것을 불러오는 쪽에서는 해당 객체에 접근하여 내보내진 데이터들을 사용할 수 있다. 참고로 exports라는 변수도 존재하는데, 이는 module.exports 객체를 가리킨다. 따라서 module.exports의 프로퍼티를 수정하든 exports의 프로퍼티를 수정하든 효과는 같다. 그러나 exports 자체에 다른 값을 대입하는 것은 안 된다. 더 이상 module.exports 객체를 가리키지 않게 되기 때문이다. 실제로 내보내지는 것은 module.exports 객체이다.

2-3. 모듈 불러오기 (require)

외부 모듈의 데이터를 불러오려면 require("경로") 함수의 반환 값을 변수에 대입하면 된다. require() 함수가 반환하는 것은 해당 모듈의 module.exports 객체이다.
 

3. ES6 기반의 모듈 내보내기 및 불러오기 (export, import)

3-1. 개요

앞서 배경 설명에서 언급했듯이, 이는 브라우저 단에서도 쉽게 JavaScript의 모듈화가 가능하도록 ES6부터 도입된 방식이다. 모듈화 시스템답게 각각의 모듈(파일)마다 독립적인 파일 스코프를 가지고 있어서, 모듈 내에 var로 선언한 변수는 더 이상 window 객체의 프로퍼티가 아닌 파일 스코프의 변수로 존재하게 된다. 즉 기본적으로는 다른 모듈의 데이터를 참조할 수 없기 때문에 충돌도 발생하지 않는다. 이때 다른 모듈의 데이터를 참조하거나 자신의 데이터를 노출시키고 싶을 때 사용하는 것이 바로 export, import 키워드이다. export 키워드로 자기 자신의 데이터를 외부로 내보낼 수 있고, import 키워드로 외부 모듈의 데이터를 불러올 수 있다.
이러한 모듈 시스템을 브라우저에서 사용하려면 <script> 태그에 type="module" 어트리뷰트를 추가해야 한다. 그러면 그 안에 작성된 JavaScript 코드들은 ES6 기반의 모듈 내보내기 및 불러오기 방식을 지원하게 된다. 이때 불러오는 파일이 모듈임을 명확히 하기 위해 <script type="module"> 태그로 불러오는 JavaScript 파일의 확장자는 mjs로 설정하도록 권장되고 있다.
ES6 기반의 모듈 시스템은 CommonJS 방식에 비해 코드의 직관성이 좋고, 비동기 방식으로 작동하면서 불러오는 모듈의 실제로 사용되는 부분들만 로드하기 때문에 성능적으로도 효율적이라고 할 수 있다. 그러나 이는 아래와 같은 단점들을 가지고 있어서 아직까지는 Webpack 등의 모듈 번들러를 이용하여 미리 의존성이 해결된 형태의 번들 JavaScript 파일을 제공하는 방식이 더 선호되는 경향이 있다.
  • IE(인터넷 익스플로러)를 포함한 몇몇 구형 브라우저는 ES6 모듈 시스템을 지원하지 않는다.
  • 브라우저의 ES6 모듈 시스템을 사용하더라도 어차피 트랜스파일링이나 번들링은 필요하다.
💡
Babel 및 Webpack의 간단한 동작 원리에 대해서는 이 포스팅을 참고하자. 단 이는 간단한 개념 설명일 뿐이니, 보다 자세한 내용은 다음 링크를 읽어보자. 개인적으로 감명 깊게 읽은 매우 매우 감사한 포스팅이다.

3-2. 모듈 내보내기 (export)

  • Named Export: 정해진 이름으로 내보내기
  • Default Export: 기본 내보내기 (이름을 정하지 않음. 최대 하나만 가능.)

3-3. 모듈 불러오기 (import)

 

4. 참고: ReactJS에서 NPM 패키지 모듈 불러오기

앞서 말했듯 NPM 패키지 모듈들은 CommonJS를 기본 모듈 시스템으로 채택한다. 즉, 모듈을 내보내고 불러오는 것에 있어 require, module.exports 등을 사용한다는 말이다. 그러나 실제로 ReactJS 등의 라이브러리를 활용하여 프론트 엔드 개발을 할 때는 NPM 패키지 모듈을 불러오기 위해 ES6 문법의 코드를 작성하는 경우가 많다(import, export 등). 그런데 왜 문제가 발생하지 않을까? 이는 Babel 등의 컴파일러가 import, export 등의 코드를 CommonJS 기반의 코드로 변환해주기 때문이다. 그러고 나면 Webpack에 의해 JavaScript 모듈들의 번들링이 가능해진다. 변환 규칙은 대략 다음과 같다(실제로는 더 복잡할 수 있다).
💡
Summary
ES6의 모듈 내보내기 코드를 CommonJS의 모듈 내보내기 코드로 변환할 때 디폴트 내보내기는 default 프로퍼티에 대응된다. 그리고 ES6의 모듈 불러오기 코드를 CommonJS의 모듈 불러오기 코드로 변환할 때의 핵심은, “ES6의 모듈 내보내기 코드는 내가 약속한 형태대로 올 것이니 그대로 믿고, CommonJS의 모듈 내보내기 코드는 믿지 않고 내가 약속한 형태가 되도록 가공하는 것”이다. 이때 주의해서 생각해봐야 하는 경우는 바로 스타(*) 불러오기와 디폴트 불러오기이다.
 
 
본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.
말풍선
댓글 0
좋아요 2
    아직 작성된 댓글이 없어요.
사용자