특정한 기능을 하는 독립적인 코드 단위를 뜻합니다.
모듈은 관리가 용이하고 재사용성이 증가한다는 장점이 있어 → 프로그래밍 언어에서는 모듈 시스템이 필수가 되었습니다.
자바스크립트도 프로그래밍 언어이기 때문에 모듈 시스템이 존재하는데 대표적으로 ESM(ECMAScript Module)
이 있습니다.
// math.js
export function add(a,b){
return a + b
}
// main.js
import { add } from "./math.js"
자바스크립트에는 이 외에도 CJS, AMD, UMD
등 다양한 모듈 시스템이 존재합니다.
대표적으로 4개의 모듈 시스템이 있습니다.
각 모듈 시스템의 등장 순서는 CJS
→ AMD
→ UMD
→ ESM
순 입니다.
처음 CJS가 등장하기 전(2009년)까지는 자바스크립트에 별다른 모듈 시스템이 없었는데,
이유는 다음과 같습니다.
그러다가 자바스크립트의 인기가 높아지면서 브라우저마다 본인들마다의 자바스크립트를 만들다보니 상호 호환성에 문제가 발생했습니다.
이러한 문제를 해결하기 위해 자바스크립트 표준을 정하기로 했고 이것이 지금의 ECMAScript
입니다.
이러한 표준을 가지고 점점 발전하면서 브라우저 뿐만 아니라 서버 개발분야로도 넓혀가고자 했고 2009년 초 CJS
(CommonJS)가 등장했습니다.
CommonJS
exports
로 모듈을 내보내고 require
로 모듈을 불러오는 방식자바스크립트를 서버에서도 즉, 브라우저 외부 환경에서도 사용하고 싶으나 파일 읽기, 쓰기 기능이 없고
웹서버나 DB 등을 연동하는 interface가 부족하며, 패키지 매니저와 모듈 시스템이 없다는 점이 가장 큰 걸림돌이었고 이를 해결하기 위한 그룹이 CommonJS 그룹
이었습니다.
이들 그룹에서 모듈 스펙(CJS)과 패키지 스펙(Package.json 과 같은 관리 방식)을 제안했고 이를 통해 서버 측 개발에서도 자바스크립트를 사용할 수 있는 기반이 마련되었습니다.
크롬은 CJS보다 1년 먼저 출시되었고 내부 엔진인 V8 자바스크립트 엔진
은 압도적 성능을 보여주었습니다.
즉, 자바스크립트 실행 속도를 획기적으로 향상시킨 브라우저의 등장이었을겁니다.
그래서 당시를 생각해보면 CommonJS 그룹에서는 자바스크립트를 브라우저 외부 환경에서도 사용하게 하기 위해 여러 노력을 하고 있었고 구글에서 크롬 브라우저 V8엔진을 통해 자바스크립트 실행 속도를 획기적으로 개선했습니다.
이러한 변화들을 Ryan Dal 이란 사람이 (지금은 Deno를 개발하고 있는걸로 알고 있습니다.) 눈여겨 보았고 CommonJS의 모듈 시스템
과 V8 엔진의 성능
을 결합하여 서버에서도 빠르게 실행할 수 있는 런타임 환경인 Node.js
를 만들었습니다.
이렇게 만들어진 Node.js는 자바스크립트 라는 익숙한 언어와 높은 성능으로 인해 점차 인기를 얻어갔고
이 덕분에 CommonJS도 덩달아 많은 관심을 받게 되었습니다.
뿐만 아니라 2010년에 NPM
이라는 자바스크립트 패키지 매니저가 등장하면서 Node.js, CommonJS와 함께 서버 사이드 자바스크립트 생태계를 확장하게 됩니다.
서버 사이드 자바스크립트 생태계가 날로 발전하는 한편, 브라우저 자바스크립트 진영에서도 웹 어플리케이션이 복잡해짐에 따라 모듈화가 절실해졌습니다.
그러나 CommonJS 방식을 브라우저에 지원하기 어려웠습니다. (CJS는 동기적으로만 동작, 브라우저에 적합한 비동기 방식을 지원하지 않음)
그래서 브라우저 환경에서의 개발자들은 CJS와 별개로 비동기 모듈시스템을 고민했고 그 결과가
AMD
입니다.
즉, AMD
(Asynchronous Module Definition)는 브라우저용 비동기 JS 모듈 시스템
(구현체가 아닌 명세) 입니다.
구현체는 Require.js / dojo toolkit 과 같은 것들이 있습니다.
// math.js
define(function(){
return {
add : function(){}
}
})
// main.js
require(["math"], function(math){
var sum = math.add(5,3)
})
그런데 이미 CJS에 익숙해진 사람들이 AMD를 사용하지 않고 CJS를 그대로 브라우저에서 사용하고 싶어했고
이러한 고민의 끝에 browserify
라는 번들러가 등장했고 이는 모던 번들러의 시초라고 불리고 있습니다.
브라우저파이는 CJS 문법이 브라우저에서 직접 동작하지 않는 문제를 해결하기 위해 분리되어 있던 모듈 파일을 하나로 합쳐서(번들링)
브라우저 호환코드로 변환해줍니다.
그러다보니 AMD 방식으로 만들어진 JS와 browserify를 이용한 CJS 방식의 JS 파일 간 상호 호환이 되지 않는 문제가 발생했습니다.
그래서 이러한 문제를 해결하기 위한 즉, 어떤 환경이든 호환이 되는 모듈 시스템인 UMD
가 등장합니다.
그러나UMD
역시 구현체는 아니고 모듈 간 호환성을 제공하기 위한 자바스크립트 모듈 패턴
입니다.
정리하면 UMD는 UMD 코드 패턴을 사용함으로서 어느 환경에서던지 동작하는 모듈을 만들자는 목적으로 환경별 분기 로직을 넣은 코드 템플릿
이라고 할 수 있습니다.
위와 같은 모듈 스펙 또는 패턴들의 등장으로 자바스크립트 생태계의 모듈 시스템이 발전해가고는 있었지만
정해진 표준이 없었기에 혼란이 존재했습니다.
이러한 혼란을 잠재우고자 2015년에 드디어 ES6(ES2015)
가 등장했으며, 여기에 공식 모듈시스템인 ESM
이 포함되었습니다.
ES6 내용
모듈 기능(ESM)
import add from "./add.mjs";
export default add;
export {add};
자바스크립트의 공식 모듈 시스템이 도입됨으로서 CJS, AMD, UMD 없이도 표준방식인 ESM을 사용할 수 있었습니다.
다만, 표준이라고 해서 모든 것이 해결되지는 않았고 여러 문제가 발생했는데
하나의 JS 파일에서 다른 JS 파일들을 import 하는 식으로 모듈을 개별적으로 로딩
함에 있어 성능 문제(브라우저 환경)이러한 문제를 해결하기 위해
트랜스파일러
**로 코드 변환하여 문제 해결
트랜스파일러(대표적으로 Babel, SWC)
를 활용여러 개의 JS 파일을 하나의 JS 파일로 합치는 툴
을 의미.cjs
/ .mjs
와 같이 방식별로 파일확장자를 구분했고 type: "module"
과 같이 기본 모듈 시스템 방식을 지정해주기도 했습니다.이 링크를 통해 구매하시면 제가 수익을 받을 수 있어요. 🤗