모듈 - CommonJS와 ES Modules

velgmzz·2023년 2월 10일
0

JavaScript

목록 보기
2/2
post-thumbnail

모듈?

애플리케이션의 크기가 커지면서 파일을 분리해야 하는 시점이 있고, 파일을 각각 하나의 모듈(Module)이라 하고, 프로그램을 구성하는 구성요소 일부이다. 모듈은 하나의 파일, 스크립트 하나가 모듈 하나이다.

JS의 모듈

초기의 스크립트는 크기도 작고 기능도 단순했던 시기가 있었다. 단순했기에 파일을 분리할 필요가 없었고 스크립트 내에 그저 변수 몇 개, 함수 몇 개로 이루어져 있었다.

var message = 'Hi~';
function hello() {}
function add() {}
... //초기 스크립트의 가정

모듈 스코프의 필요성

초기 모듈화는 스크립트 코드를 파일로 나눠 <script> 태그로 불러오는 방식을 사용했다.
스크립트는 파일마다 독립적인 파일 스코프를 가지지 않고 하나의 전역 객체를 공유하여 사용한다.

<script src="./foo.js"></script>
<script src="./bar.js"></script>
// foo.js
var number = 1;
var number = 2;

시간이 흘러 서서히 JavaScript의 개발 규모가 커지면서 web 안에서 캘린더, 지도 등 복잡한 web application(webApp)이 등장하며 여러 가지 문제가 발생하며 다음과 같다.

  • 전역 변수의 충돌
  • 다른 사람의 코드를 이용할 때 의존성 관계 확인이 어려움
  • 파일을 로드하는 순서를 생각해야함
<script src="jquery.js"></script>
<script src="velgmzz.js"></script>
<script>
  window.$
  window.velgmzz //여기서도 접근 가능
</script>
<script>
  window.velgmzz
</script>

위에서 스크립트는 전역 변수로 공유가 된다고 했다. jquery와 velgmzz을 불러오고 보니 첫 번째 스크립트에서도 velgmzz이라는 변수를 접근할 수 있으면서 충돌의 위험이 커진다.

다른 사람의 코드를 사용하거나 남이 나의 코드를 쓸 때도 충돌 같은 문제가 발생하는 걸 원하지 않았다.
이러한 문제들을 해결하기 위해 AMD, CommonJS가 등장하게 되었다.

CommonJS?

브라우저만 지원하는 JavaScript를 Server Side 및 데스크탑 애플리케이션에서도 지원하기 위해 만들어진 스펙, commonjs에 의해 module system이 만들어졌다. Node.js에서 이 표준을 사용하고 있어 유명하다.

CommonJS의 공식홈페이지 소개글 // javascript: not just for browers any more!

모듈화

CommonJS가 만들어지면서 많은 기능들을 표준화하고자 했는데 우리가 집중해야 할 것은 모듈화이다. 모듈화는 아래와 같이 세 부분으로 이루어진다.

  • 스코프 : 모든 모듈은 자신만의 독립적인 실행 영역이 있어야 한다.
  • 정의 : 모듈 정의는 exports 객체를 이용한다.
  • 사용 : 모듈 사용은 require 함수를 이용한다.

CommonJS의 사용

모듈화가 되면서 JavaScript에도 독립적인 영역이 생기게 되었다. 그 영역 밖으로 내보내고(exports) 사용하는 방법(require)이 생겼다.

// cal.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

exports.add = add;
exports.subtract = subtract;

exports로 함수 add와 subtract를 내보내고, 다른 파일에서 사용할 수 있다.

// app.js
const cal = require('./cal.js');

cal.add(1, 2); // 3
cal.subtract(2, 1); // 1

require를 통해서 가져와 사용할 수 있다.

NodeJS의 exports와 module.exports

CommonJS에서는 module.exports라는 객체를 갖고 있지 않고 바로 exports를 사용한다.

여기서 NodeJS는 모두 사용하는데, exports와 module.exports의 차이에 대해 짚고 넘어가겠다.

  • module.exports
//module.js
const tom = {
  name: 'Tom',
  intro: 'Hi'
}

module.exports = tom;
//main.js
const user = require('./module');
console.log(user);

output

{ name: 'Tom', intro: 'Hi' }

  • exports
const tom = {
  name: 'Tom',
  intro: 'Hi'
}

exports = tom;
//main.js
const user = require('./module');
console.log(user);

output

{}

module.export로 가져온 객체는 출력이 잘되는반면 exports는 빈 객체가 출력된다.
exports 객체와 module.exports 객체는 동일하며, exports는 module.exports를 참조하고 있다.
exports = tom;은 module.exports에 대한 참조가 끊어지고 변수 tom의 값을 가진다.

  • exports와 module.exports
const module = { exports: {} };
const exports = module.exports;

function require(path) { // 가져올때의 require는 함수
  ...
  return module.exports;
}

ES Modules?

JavaScript를 만드는 표준 기구인 ECMAScript는 모듈 시스템에 대한 표준을 만들어 발표했다.
JS로 개발한다면 아마도 가장 익숙한 import, export 구문을 사용하는 방식이다. 현재 모든 브라우저에서 지원하고 있고 표준 기구에서 발표했기에 JavaScript 자체로 모듈에 대한 문법을 갖게 되었다는 의미다.

import, export

export를 통해 변수, 함수를 내보낼 수 있다. 앞에 prefix로 붙여주기만 하면 된다.

export const POST_REQUEST = 'POST_REQUEST';
export const add = (a, b) => a + b;
// 또는
const add = (a, b) => a + b;
export default add;

이렇게 export를 붙여 내보낸것들은 import를 통해 가져와 사용할 수 있다.

import { POST_REQUEST, add } from './path';
import add from './path';

여기서 눈여겨봐야 될 것은 export const addexport default add인데 살짝 차이점이 있다. default를 사용해 내보내는 것은 모듈 내에서 한 번만 사용할 수 있고 export const add와 같이 default가 없다면 여러 번 사용할 수 있다. 또 export const add는 import를 할 때 {}로 묶어서 불러와야 한다. default로 내보낸 add는 import한 곳에서 이름을 자유롭게 지정할 수 있다.

import addFunction, { add } from './path';

결론

모듈이 무엇인지, JavaScript의 모듈은 어떻게 변해왔는지, 가장 많이 보게 되는 CommonJS, ES Modules를 간단히 정리했다. 기술의 개념을 이해하기 위해서는 왜 등장했는지를 함께 이해하며 공부한다면 좀 더 기억에 잘 남을 것이라 생각한다.
위의 글은 일부분일 뿐 AMD, WebPack등 아직도 많은 개념이 남아있다. 나머지는 다음 글에서 작성해보려 한다.

profile
정리하며 공부하는 블로그, React/Next를 공부합니다

0개의 댓글