[48장] 모듈

2022. 2. 16. 14:06책/자바스크립트 딥다이브

1. 모듈의 일반적 의미
모듈 : 애플리케이션을 구성하는 개별적 요소로서 재사용 가능한 코드 조각
보통 모듈은 기능을 기준으로 파일 단위로 분리하며, 모듈이 성립하기 위해선 모듈 자신만의 파일 스코프(모듈 스코프)를 가질 수 있어야 한다.

원래 모듈의 자산(모듈內 변수, 함수, 객체 등등 온갖 것들)은 기본적으로 비공개 상태다.
이 말은 모듈의 모든 자산은 캡슐화되어 다른 모듈에서 접근할 수 없다는 뜻이고,
이는 곧 모듈은 개별적 존재로서 애플리케이션과 분리되어 존재한다는 뜻이다.

ㅇexport / import / module consumer

그런데 애플리케이션과 분리돼 개별적으로 존재하면 재사용이 불가능하므로 존재 의미가 없게 된다. 이때문에 공개가 필요한 자산에 한정하여 명시적으로 선택적 공개가 가능한데, 이를 export라고 한다.

공개(export)된 모듈의 자산은 다른 모듈에서 재사용이 가능하고, 이 자산을 사용하는 모듈을 모듈 사용자(module consumer)라고 한다.

모듈 사용자는 모듈이 공개(export)한 자산 중 일부 또는 전체를 선택해 자신의 스코프 내로 불러들여 재사용할 수 있는데, 이를 import라고 한다.

모듈은 기능별로 분리해 개별적 파일로써 애플리케이션을 구성할 수 있고, 재사용성을 높이면서 개발 효율성과 유지보수성을 높일 수 있다.

2. 자바스크립트와 모듈
자바스크립트는 태생이 쩌리였어서 원래 모듈 시스템을 지원하지 않았다. 다시 말해, 모듈이 성립하기 위해 필요한 파일 스코프와 import / export를 지원하지 않았다.
<script> 태그를 써서 자바스크립트 파일을 로드할 순 있어도 파일마다 독립적인 파일 스코프를 갖지는 않는다. 따라서 js파일을 여러개로 분리한들 실상은 하나의 자바스크립트 파일 내에 있는 것처럼 동작한다 (= 하나의 전역을 공유한다)

실상이 이렇다보니 모듈 시스템을 구현하기 위해 CommomJS와 AMD(Asynchronous Module Definition)이 제안됐고, Node.js 환경에선 CommonJS를 채택해(CommomJS사양과 100% 동일한 수준까지는 아님) 모듈 시스템을 지원하고있다(ECMAScript 표준사양 X)

* 따라서 Node.js 환경에선 파일별로 독립적인 파일 스코프(모듈 스코프)를 갖는다

3. ES6 모듈(ESM)
ES6에서 클라이언트 사이드 자바스크립트에서도 동작하는 모듈 기능을 추가했다 (IE 빼고는 거의다 지원중)
ES6 모듈(ESM) 사용법은 <scirpt type="module" src="app.mjs"> 이라고 type 어트리뷰트를 추가하면 js파일이 모듈로서 동작한다. 또한, 일반적인 자바스크립트 파일과 구분하기 위해 확장자를 mjs라고 사용하는게 권장된다

1) 모듈 스코프
ESM은 독자적인 모듈 스코프를 갖는다. 따라서 모듈 내에선 var 키워드로 변수를 선언해도 전역 변수가 되지 않고, 따라서 window 객체의 프로퍼티도 아니게 된다.

2) export 키워드
모듈은 독자적인 스코프를 가지므로, 외부 모듈에서도 재사용하고 싶은 자원이 있다면 export 키워드를 사용한다.
개별적으로 export 키워드를 붙여가며 공개할 수도 있고, 객체로 묶어서 한번에 공개할 수도 있다.

// 변수 공개하기 export const pi = Math.PI; // 함수 공개하기 export function square(x) { return x * x; } // 클래스 공개하기 export class Person { constructor(name) { this.name = name; } } // 전부 하나의 객체로 묶어서 공개하기 export { pi, square, Person };

만약 하나의 값만 export 한다면 export default 키워드를 사용해도 된다.
단, const / let / var 키워드는 사용할 수 없고
import시 { } 없이 아무 이름으로 불러오면 된다

3) import 키워드
다른 모듈이 공개(export)한 식별자 이름으로 import하며, 파일 확장자를 함께 작성한다.
import { pi, square, Person } from './sub.mjs'

export한 모든 식별자를 하나의 객체로 모아서 import 하는것도 가능하며,
import * as sub from './sub.mjs'

export한 개별 식별자의 이름을 따로 지정해서 import 하는것도 가능하다
import { pi as PI, square as sq, Person as P } from './sub.mjs'

예시) main.mjs 에서 sub.mjs 모듈 불러와 사용해보기

<script type="module" src="main.mjs"></script>

html 파일에서 main.mjs를 애플리케이션의 진입점(entry point)로 잡았다.
따라서 sciprt태그로 main.mjs를 로드해준다.
이때 sub.mjs는 app.mjs의 import문으로 로드되는 의존성(dependency)이므로 별도의 <script> 태그로 로드할 필요가 없다.

이제와서 얘기하는거지만 사실 ESM보다는 별도의 모듈 로더를 사용하는 것이 일반적이며, 그 이유는
- IE를 포함한 구형 브라우저에선 ESM 지원 X
- ESM을 사용하더라도 트랜스파일링이나 번들링이 필요함에는 변함없음
- ESM이 아직 지원하지 않는 기능(bare import 등등)이 있고 점차 해결되고는 있지만 아직 몇 가지 이슈가 존재함

' > 자바스크립트 딥다이브' 카테고리의 다른 글

[47장] 에러 처리  (0) 2022.02.16
[46장] 제너레이터와 async/await (2)  (0) 2022.02.15
[46장] 제너레이터와 async/await  (0) 2022.02.15
[45장] 프로미스(3)  (0) 2022.02.15
[45장] 프로미스(2)  (0) 2022.02.15