기존의 자바스크립트는 모듈이라는 개념이 부족하여 각 모듈(또는 파일)간의 의존성 처리에 제한이 있었다. 고전적인 웹 프로젝트에서 자바스크립트를 사용하는 방법을 살펴보면, HTML 파일 내부에 <script>
태그를 삽입하여 모듈을 로드하고 있다. 하지만 이러한 방식은 한가지 문제가 있는데, 자바스크립 파일끼리 서로 모듈을 공유하는데 제약이 없다는 점이다.
그 이유는 script 태그로 모듈은 모두 window객체의 속성이기 때문에 서로 다른 파일에 위치하면서도 모든 객체를 공유할 수 있기 때문이다. 이처럼 각 자바스크립트 파일이 독립적으로 존재하지 못해 발생하는 여러 문제들(예를 들어 다른 파일에서 같은 이름의 변수를 사용하는 경우) 때문에 하나의 모듈로 관리하기 위한 다양한 패턴(모듈 패턴, 즉시실행함수 등) 을 사용하여 의존성을 관리할 수 밖에 없었다.
이를 해결하기 위한 수단으로 모듈이라는 개념을 도입하여 정의한 방법이 CommonJs와 AMD이다. 이 둘은 내부적으로 모듈 간의 의존성이 지원되지 않는 상태로 만들어 졌는데, ES6에 이르러 언어 내부적으로 자바스크립트 모듈 의존성을 지원하게 되었다.
ES6 모듈은 기본적으로 CommonJs 와 AMD 모듈을 혼용해서 사용할 수 있다. 모듈을 가져오는 부분에 require
와 import
를 같이 쓰더라도 문제 없이 동작한다.
- require : 자바스크립트 자체가 지원하는 패키지 읽는 방법
- import : ES6의 사양으로 새로운 패키지 읽는 방법
모듈을 정의 한다는 것은 다른 모듈에서 사용할 수 있도록 하나의 모듈로써 노출하겠다는 의미이다.
ES6
// ①모듈 전체를 export, 파일내 한번만 사용가능
let module = {};
export default module
// ② 모든 속성을 export
export *;
// ③ 함수를 직접 export
export function moduleFunc(){};
let property = "some property";
let property2 = "some property2";
export {property, property2}
CommonJs
// ① 모듈 전체를 export
module.exports = module
// ② 함수를 직접 export
exports.moduleFunc = function() {}
ES6
// ① 모듈 전체를 import
import module
import module as myModule
// ② 모든 속성 import
import * from module
// ③ 특정 멤버(함수 등)만 import
import {moduleFunc, moduleFunc2} from module
CommonJs
// ① 모듈 전체를 import
var module = require('./someModule.js')
// ② 모든 속성 import
// (위의 module 객체에 모든 속성이 담아져 온다.)
// ③ 특정 멤버(함수 등)만 import, 위의 module을 이용한다.
module.moduleFunc
CommonJs방식으로 모듈을 내보낼때는 ES6처럼 명시적으로 선언하는 것이 아니라 특정 변수나 그 변수의 속성으로 내보낼 객체를 세팅해줘야 한다. 특히, 제일 햇갈리는 부분이 바로 유사해 보이는 export
변수와 module.exports
변수를 상황에 맞게 잘 사용해야 한다는 점이다. 기본적으로 2가지 규칙만 기억하면 된다.
1. 여러개의 객체를 내보낼 경우 -> `export`변수의 속성으로 할당
2. 딱 하나의 객체를 내보낼 경우 -> `module.exports`변수 자체에 할당