ESM (ECMAScript Modules), CJS(common JS)Frontend/웹 관련 지식2024. 11. 19. 00:14
Table of Contents
nit) history
- JS 진영에는 두가지 모듈 시스템이 존재한당. ESM, CJS
- ESM은 FE 개발하는 사람이라면 자연스럽게 사용하는 import를 이용해 모듈을 이용하는 방법이다
import {get} from 'lodash';
- CJS는 백엔드 서버를 위해 node.js 서버를 개발하거나 웹 어플리케이션 구축을 위해 react나 next.js에서 config.js 파일을 설정할 때 사용해봤을 것이다
const { chicken } = require('food');
- 처음 Javascript가 등장하고나서 시간이 흐르고 흘러.. Ajax가 등장하고부터 웹 페이지를 서버와 통신을 통해 비동기적으로 업데이트하는 방식이 등장했고 이를 커버할 수 있는(성능이 좋은) V8 엔진이 등장하며 주목받기 시작했다.
- 이러한 변화의 바람은 뒷단에서 사용되는 Javascript 진영에 변화의 바람을 일으켰다
- 백엔드에서 개발할 수 있는 환경인 node.js가 등장했고 기존 javascript 표준에 존재하지 않는 파일 시스템과 네트워크를 관리할 수 있는 API가 없다는 문제를 해결하기 위해 BE 진영에서 새로운 표준으로 Common JS가 등장했다
- 추가로 FE에서만 쓰이는 언어가 아닌 범용적으로 사용될 수 있는 언어로 쓰이기 위해 모듈화에 대한 이슈라이징을 했다
- 호환되는 표준이 존재하지 않음
- DB에 연결하는 표준이 존재하지 않음
- 의존성 문제까지 해결하는 공통 모듈 저장소가 없음
- Common JS는 위의 문제를 모듈화를 통해 해결하고자 했고, 모듈을 어떻게 정의하고 어떻게 사용일 것인가에 대해 해결방안을 만들었다.
- 모듈은 자신만의 독립적인실행 영역이 존재해야하고 Server Side에서는 각각의 파일별로 scope가 존재해서 당시 var(전역변수)만 지원하던 시절에도 하나의 파일에 하나의 모듈을 작성하면 되었지만 브라우저에서는 그렇지 않았다..
- Common JS는 위와 같은 문제로 해결!
- 브라우저는 파일 단위 스코프가 없음 ㅠ
- FE에서는 여전히 모듈을 관리할 수 있는 표준이 존재하지 않았고 CommonJS를 흉내내어 require를 사용하기도 했지만 여러가지 문제가 있었다
- script 태그를 파일이 로딩되는 순서까지 고려해서 사용해야 하며 비동기 문제와 전역변수 문제도 존재했다
- 전역변수 문제 -> 어떤 파일 A에서 a라는 변수를 사용하고 후에 B라는 파일에서 b라는 변수를 쓴다면 덮어씌워짐
- 비동기 문제 -> 브라우저는 javascript를 저장하지 못하고 매번 불러와서 사용하지만 스크립트가 언제 로딩될지 모르기 때문에 비동기 문제가 발생함
- script 태그를 파일이 로딩되는 순서까지 고려해서 사용해야 하며 비동기 문제와 전역변수 문제도 존재했다
- 또한 FE와 BE의 표준이 맞지않는 문제도 존재했다
- 그러다가 2015년 ES6와 등장으로 ECMAScript module이 등장했다!
ESM vs Common JS
Tree shaking
- 빌드 타임에 사용되지 않는 코드를 제거하여 번들 사이즈를 줄이는 최적화 기법!
- ESM은 정적으로 모듈을 가져오지만 CJS는 동적으로 모듈을 불러오기 때문에, 대체적으로 ESM만 Tree shaking이 가능하다
- CommonJS는 module.exports의 객체라는 특성 때문에, 빌드 타임에서는 모듈에서 어떠한 값이 불러와서 사용해질 수 있을지 가늠할 수 없다.
- 따라서 bundler는 Common JS로 되어 있는 모듈의 성능을 위해 하나의 거대한 클로저로 합쳐버린 대신, 무엇이 실행될 지를 결정하는 작업을 포기한다
- 이와 같은 이유로CJS는 빌드 타임에 정적 분석을 하지 못하고 모듈 관계를 런타임에서 확인할 수 ㅣㅇㅆ다.
- ESM은 정적인 구조로 모듈끼리 의존하도록 강제된다.
- import path에 동적인 값을 사용할 수 없고, export는 항상 최상위 스코프에서만 사용할 수 있게 되어있다.
- 이와 같은 이유로 ESM은 빌드 단계에서 정적 분석을 모듈의 의존성을 확인해서 Tree shaking을 할 수 있다.
실행하는 방식
- CommonJS에서는 모듈을 가져오는 방식이 동기로 이루어진다.
- require() 호출은 실행 즉시 해당 모듈을 로드하고 반환한다.
- 따라서 promise나 콜백 호출을 리턴하지 않는다. require()는 브라우저 or 네트워크에서 모듈을 읽어서 즉시 스크립트를 실행한다.
- 따라서 스스로 I/O나 부수효과 (side effect)를 실행하고 module.exports에 설정되어 있는 값을 리턴한다.
- ESM은 모듈 로더를 비동기 환경에서 실행한다.
- 먼저 가져온 스크립트를 바로 실행하지 않고, import와 export구문을 찾아서 스크립트를 파싱한다.
- 그 다음 ESM 모듈 loader는 가져온 스크립트를 비동기로 다운로드 하여 파싱해서 import된 스크립트를 가져오고, 더 이상 import 할 것이 없어질 때까지 import를 찾은 다음 dependencies의 모듈 그래프를 만들어 낸다.
- 이후 스크립트는 실행될 준비를 마치게 된 후, 해당 스크립트에 의존하고 있는 스크립트들도 실행할 준비를 마치게 되며 마침내 실행된다.
Name Exports
- CJS는 실행단계에서 연산하기 때문!
Top Level Await
- ES2022에서 나온 기능으로 모듈의 최상위 스코프에서 비동기 동작을 await하여 사용할 수 있다.
- 기존에는 async 키워드가 있는 스코프 내에서만 await를 통해 해당 스코프에서 비동기 동작이 완료되기까지 블로킹할 수 있었는데 모듈단위에서 await를 통해 특정 비동기 함수의 동작이 완료되기까지 하위 모듈의 동작을 막을 수 있다.
- CommonJs는 지원 안하지롱
- require()는 동기적으로 결과를 반환해야 하지만, await가 완료될 때까지 기다리지 못한다
- module.exports에 어떤 값이 올지 모름 ㅎㅎ
ESM에서 비동기란 ?
- 사실 ESM에서 어떻게 비동기라는 단어가 쓰이는지에 대해 이해가 잘 가지 않아서 추가로 정리해본다..!
- ESM(ECMAScript Modules)에서 "비동기"는 모듈을 로드하거나 가져오는 작업이 비동기적으로 이루어진다는 의미이다.
- 즉, 모듈을 가져오는 과정이 다른 코드 실행을 블로킹(blocking)하지 않고 백그라운드에서 진행된다.
- 이로 인해 JavaScript가 본래 가진 비동기 특성과 잘 맞아 효율적인 실행이 가능하다.
주요 특징
- import의 비동기성
ESM의 import 문은 브라우저나 Node.js 환경에서 모듈을 로드할 때 비동기적으로 작동한다- 이 과정에서 모듈을 다운로드하고, 파싱하고, 실행하는 작업이 이루어진다.
- 그러나 이러한 비동기 작업은 최상위 레벨에서만 사용 가능하며, import 자체는 동기적으로 선언된다.
- 실행 순서 보장
- 모듈은 비동기로 로드되지만, 의존성 그래프에 따라 모듈 간의 종속성이 해결된 후 실행된다.
- 즉, 필요한 모든 모듈이 준비된 후에 코드를 실행하므로 개발자는 실행 순서를 걱정하지 않아도 된다...!
비동기 특성이 중요한 이유
- 빠른 페이지 로드
브라우저 환경에서는 필요한 모듈을 백그라운드에서 로드하므로 페이지 렌더링에 방해되지 않다. - 동적 모듈 로드
런타임에 필요할 때 모듈을 로드함으로써 초기 로드 시간을 단축하거나, 특정 조건에서만 모듈을 불러올 수 있다. - 병렬 처리 가능
여러 모듈을 동시에 비동기적으로 로드할 수 있으므로 성능이 최적화된다.
정리
- ESM에서 비동기는 모듈 로드와 실행을 효율적으로 처리하기 위한 핵심 요소입니다. 이를 통해 JavaScript 애플리케이션의 성능과 확장성을 개선할 수 있다!
CJS
// sum.js
module.exports.sum = (a, b) => a + b;
// calc.js
const { sum } = require('./sum');
add(96, 05);
ESM
// sum.js
export const function sum(a, b) {
return a + b
}
// calc.js
import { sum } from './sum.js';
add(96, 05);
Ref
'Frontend > 웹 관련 지식' 카테고리의 다른 글
useState, react state 돌아보기 =( (0) | 2024.11.24 |
---|---|
dist랑 node_module이 뭐였더라.. (1) | 2024.11.24 |
javascript IOC (0) | 2024.05.07 |
Semantic Web (시맨틱 웹) (0) | 2022.09.16 |
SPA, MPA, MVC (0) | 2022.09.16 |
@덕구공 :: Duck9s'
주니어 개발자에욤
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!