목표
javascript의 모듈 시스템의 역사와 필요성에 대해 이해하고 이를 최대한 잘 활용할 수 있게 한다.
javascript는 브라우저를 위해 만들어진 간편한 언어였지만, 이것을 서버 측면에서도 사용하고자 하는 수요는 지속적으로 있어 왔습니다.
특히, Kevin Dangoor는 JS의 다음과 같은 아쉬움을 지적해왔습니다.
1. 파일이나 디렉터리를 읽을 수 없다.
2. 웹 서버, 데이터베이스 등에 연결하거나 쿼리하기 위한 표준 인터페이스 존재하지 않는다.
3. package manager가 없다. (패키지를 배포, 관리, 설치하는 기능이 존재 X)
4. module system이 없다. (다양한 모듈들을 쉽게 load할 수 없고, 네임스페이스를 구분 X)
5. 전역 변수 관리 문제
앞서 Kevin Dangoor가 언급한 전역 변수 관리 문제에 대해서 더 자세히 알아보도록 하겠다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>useTodo.js Todos</title>
<link rel="stylesheet" href="todos.css"/>
</head>
<body>
<script src="../../test/vendor/json2.js"></script>
<script src="../../test/vendor/jquery.js"></script>
<script src="../../test/vendor/underscore.js"></script>
<script src="../../useTodo.js"></script>
<script src="../useTodo.sessionStorage.js"></script>
<script src="todos.js"></script>
</body>
<!-- (...) -->
</html>
이때, script 태그를 통한 방식에는 두 가지의 문제점이 발생할 수 있다.
var alertNum = 10; // index.js
var alertNum = 20; // page.js
<script type="text/javascript" src="./index.js"></script>
<script type="text/javascript" src="./page.js"></script>
// index.js
$(document).ready(function() {
console.log('READY');
});
<script type="text/javascript" src="./index.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- HTML File - script js files -->
index.js에 jquery 문법을 활용하여 페이지가 로드된 후, 콘솔에 READY라는 로그를 남기는 코드를 추가하였다. 이를 실행할 경우 에러가 발생한다.
해당 소스 코드에는 jquery 관련 cdn 파일이 먼저 불러와져야 하는데 script 태그의 순서가 잘못되어 있다. jquery cdn없이 index.js를 불러왔을 경우, jquery 문법이 정의되어져 있지 않기 때문에 오류가 발생한다.
위에 제시한 5가지 문제점을 해결하고 브라우저 뿐만 아니라, 서버, 데스크탑 등에서도 이용 가능한 javascript 모듈 시스템입니다.
CommonJS 모듈화는 아래와 같이 세 부분으로 이루어집니다.
스코프
: 모든 모듈은 자신만의 독립적인 실행 영역이 있어야 한다.
정의
: 모듈의 정의는 exports 객체를 이용한다.
사용
: 모듈 사용은 require 함수를 이용한다.
commonjs는 ECMA standards의 지원없이 독립적으로 개발되었다는 점입니다. 즉, 언어 자체로 commonjs를 포함하지 않는다는 것이었습니다.
정적으로 모듈을 분석하고 트리쉐이킹 할 방법이 없습니다. -> 번들 사이즈 문제
commonjs는 모듈을 동기적으로 로드하기 때문에 브라우저 환경에서 js코드가 화면에 렌더링되기까지 상당히 많은 시간이 소요됩니다.
commonjs는 모듈을 로드할 때 동기적으로 로드한다고 했습니다. AMD의 Asynchronouse에서도 알 수 있듯이 AMD에선 비동기적으로 모듈을 다루는 것에 대한 표준안을 다룹니다.
commonjs에서 분리되어 나온 그룹이기 때문에, 기본적으로 공통점을 지닌 점이 있습니다. require나 exports 같은 문법을 그대로 사용할 수 있습니다. AMD만의 특징이라면 define함수가 있습니다.
AMD의 define()함수(클로저를 이용한 모듈 패턴)을 이용하여 모듈을 구현하므로 전역변수 문제가 없다.
if(user.length > 0){
const math = require('./math.js')
//... Do something..
}
// 기존의 require는 함수였기에 if문 중간에 넣어도 상관없지만
// import는 모듈 시스템이라 최상단에서만 선언을 강제하고 있다.
<script src="classic.js"></script>
<script src="classic.js"></script>
<!-- 2번 실행 -->
<script type="module" src="module.mjs"></script>
<script type="module" src="module.mjs"></script>
<script type="module">import './module.mjs';</script>
<!-- 1번만 실행 -->
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
https://velog.io/@yesbb/모듈-시스템의-역사-그리고-ESM