-
[Javascript] Javascript 모듈의 종류프로젝트/Share Your Trip 2024. 1. 2. 17:30
Javasciprt 모듈이 왜 궁금했을까❓
- Vite의 번들링 원리를 깊이 이해하기 위해 관련이 있는 Javasciprt 모듈 종류에 대해 학습을 진행
Module 이란❓
- 구현한 코드의 세부 사항을 캡슐화
- 1개 이상의 값(객체, 함수, 변수 등)을 내보내어 다른 코드에서 쉽게 로드하고 사용할 수 있도록 재사용 가능한 코드 조각
Module의 조건 📌
- 코드 추상화
- 특정 라이브러리에 내재된 기능의 복잡한 구현 방식을 이해하지 않아도 된다.
- 코드 캡슐화
- 코드의 잘못된 변경을 막기 위해, 내부에 코드를 숨길 수 있다.
- 코드 재사용
- 동일한 코드를 재사용할 필요가 없다.
- 의존성 관리
- 코드를 다시 작성하지 않고 의존성 변경이 유연하게 가능하다.
Module 포맷
- ES5 이하의 버전에서는 모듈을 정의하는 공식적인 문법이 존재하지 않았다.
- 모듈을 정의할 수 있도록 도와주는 포맷들이 출시되었고, ES6부터는 모듈 포맷을 제공하기 시작했다.
Module 포맷의 종류
- CommonJS
- 비동기 모듈 정의(AMD, Asynchronous Module Definition)
- 만능 모듈 정의(UMD, Universal Module Definition)
- System.register
- ES6 모듈 포맷
CommonJS
- Browser, SSR, Desktop App 등 Javascript를 범용적인 언어로 사용할 수 있도록 조직한 그룹
- 범용적으로 사용되기 위해 명세(Specification)을 만드는 일을 함
- CommonJS 포맷은 require와 module.exports를 사용해서 의존성과 모듈을 정의
var module1 = require('./test1'); var module2 = require('./test1'); module.exports = function() { // ... }
- CommonJS는 Server Side가 목적이였으며 다음과 같은 문제들을 해결할 수 있다.
- 서로 호환되는 표준 라이브러리가 없다.
- 데이터베이스에 연결할 수 있는 표준 인터페이스가 없다.
- 다른 모듈을 삽입하는 표준적인 방법이 없다.
- 코드를 패키징해서 배포하고 설치하는 방법이 필요하다.
- 의존성 문제까지 해결하는 공통 패키지 모듈 저장소가 필요하다.
- 모듈화(Scope, Definition, Usage)
- 스코프(Scope) - 모든 모듈은 자신만의 독립적인 실행 영역을 가진다.
- 정의(Definition) - 모듈 정의는 exports 객체를 이용한다.
- 사용(Usage) - 모듈 사용은 require 함수를 이용한다.
비동기 모듈 정의(AMD)
- 필요한 모듈을 네트워크를 통해 내려받을 수 있도록 하는 것(AMD)에 대한 표준안을 다루는 그룹
- AMD는 CommonJS와 달리 브라우저 내에서의 실행을 중점을 두었고, CommonJS에서 있다가 독립하게 되었다.
- 브라우저에서 사용되며, define 함수를 사용해서 모듈을 정의한다.
define(['module1', 'module2'], function (module1, module2) { return function () {}; });
- AMD와 CommonJS에서 정의하는 모듈 명세의 차이는 모듈 로드에 있다고 한다.
- 로컬에 필요한 파일이 있어 바로 사용 가능한 상황인 Server Side에서는 CommonJS 명세가 간결하고 네트워크를 통해 내려받아야 하는 상황에서는 AMD가 유연하다고 한다.
만능 모듈 정의(UMD)
- 모듈 구현 방식을 통합하기 위해 나온 패턴
- 공식 소스코드
(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['b'], factory); } else if (typeof module === 'object' && module.exports) { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(require('b')); } else { // Browser globals (root is window) root.returnExports = factory(root.b); } }(typeof self !== 'undefined' ? self : this, function (b) { // Use b in some fashion. // Just return a value to define the module export. // This example returns an object, but the module // can return a function as the exported value. return {}; }));
- 소스 코드를 살펴보면 각 모듈의 방식을 어떻게 통합하는 지 알 수 있다.
- AMD - define()이 함수이고 define.amd 속성의 객체를 가지고 있다.
- CommonJS - module이 객체이고 module.exports 속성의 객체를 가지고 있다.
ES6 (ES2015)
- import, export를 사용하는 방식으로 모든 브라우저가 지원하는 것이 아니라는 단점이 존재
- 단점을 해결하기 위해 Bable의 @babel/plugin-transform-modules-commonjs 를 통해 변환하여 사용
// module1.js const A = () => {}; export default A;
// module2.js export const B = () => {};
// index.js import A from 'module1'; import { B } from 'module1';
- export를 사용할 때는 named export와 default export를 사용
- default는 한 번만 사용 가능하고 named export는 여러번 가능
- default를 통해 내보내면 import에서는 이름 그대로 사용 가능하고 name export의 경우는 {}를 통해 불러와야 한다.
- as(별칭)를 통해 이름을 변경하여 사용할 수 있으며, *(와일드카드)를 통해 모두 불러올 수도 있다.
Module Loader
- 모듈 포맷에 맞게 해석하고 로드하는 역할을 하며 런타임에 실행된다.
- RequireJS, SystemJS 등 모듈 로더가 있다.
- 모듈 로더 동작 순서
- 브라우저에서 모듈 로더를 로드한다.
- 모듈 로더에게 어떤 메인 애플리케이션 파일을 로드할 것인지 알려준다.
- 모듈 로더는 메인 애플리케이션 파일을 다운로드하고 해석한다.
- 필요한 경우 모듈 로더가 파일을 다운로드한다.
- 브라우저 개발자 콘솔에서 네트워크 탭을 열면, 모듈 로더에 의해 많은 파일들이 로드된 것을 볼 수 있다.
Module Bundler
- 모듈 번들러는 모듈 로더를 대체한다.
- 모듈 번들러는 런타임이 아닌 빌드 타임에 실행된다.
- Browserify, Webpack 등 모듈 번들러가 있다.
- 모듈 번들러 동작 순서
- 빌드 타임에 번들 파일을 생성하기 위해 모듈 번들러를 실행한다.
- 브라우저에서 번들 파일을 로드한다.
- 브라우저 개발자 콘솔에서 네트워크 탭을 열면, 모듈 로더에 의해 1개 파일만 로드된 것을 볼 수 있다.
- 브라우저에서 모듈 로더를 필요로 하지 않는다. 모든 코드는 번들 안에 포함되어 있다.
기타
- CommonJS는 서버측에서, AMD는 클라이언트 측에서, ES6 Modules는 Mobile 및 Desktop App 개발에서 사용된다.
- CommonJS는 모듈을 동기적으로 로드하므로 모듈이 로드될 때까지 다른 코드의 실행이 차단된다. 즉, 서버 측에서 사용할 때는 문제가 없지만 클라이언트에서 사용한다면 성능이 저하될 수 있다.
- CommonJS에서는 모듈이 로드될 때마다 새로운 객체가 생성되므로, 메모리 사용량이 높아질 수 있다.
- AMD는 모듈을 비동기적으로 로드하여 다른 코드의 실행을 차단하지 않는다.
- AMD는 모듈을 로드하기 위해 requireJS를 사용하므로 모듈을 로드할 때, 시간이 걸릴 수 있다.
- ES6 Modules는 정적으로 모듈을 로드하므로 모듈이 로드될 때까지는 다른 코드의 실행이 차단된다. 마찬가지로 클라이언트에서 성능 저하가 일어날 수 있다.
- 모듈 로드 시점을 런타임, 컴파일을 지정할 수 있다.
참고 자료 링크 🧷
https://colinch4.github.io/2021-01-14/module/
https://toylee.net/자바스크립트-모듈-시스템-비교-commonjs-vs-amd-vs-es6-modules/
'프로젝트 > Share Your Trip' 카테고리의 다른 글
[Java] Wrapper 클래스 (0) 2024.01.07 [Java] Optional 클래스 (1) 2024.01.06 [Spring boot] Maven 프로젝트를 Gradle 프로젝트로 변경 (0) 2024.01.02 [Spring boot] STS 프로젝트 IntelliJ IDEA에서 불러오기 (1) 2024.01.02 [React] React-Vite (2) 2024.01.01