ESM의 단점은, 모듈 식별자를 실행 중에 생성할 수 없다는 점, 모든 파일의 최상위에 선언되어 제어 구문 내에 포함될 수 없다는 점이다. 이는 사용자에 따라 다른 모듈을 불러야 하는 경우에 지나친 제약이 될 수 있다. 따라서 이를 극복하기 위해 비동기 임포트 ( 동적 임포트 ) 를 제공한다.
if(true) {
require(a);
} else {
require(b);
}
// strings-ko.js
export const HELLO = '안녕하세요.'
// strings-jp.js
export const HELLO = '오하이요';
// strings-en.js
export const HELLO = '하이'
const SUPPORTED_LANGUAGES = ['ko', 'en', 'jp'];
const selectedLanguage = process.argv[2];
if (!SUPPORTED_LANGUAGES.includes(selectedLanguage)) {
console.error('The specified language is not supported');
process.exit(1);
}
const translationModule = `./strings-${seletecLanguages}.js`;
import(translationModule).then((string) => {
console.log(string.HELLO);
})
import() 연산자는 문법적으로 모듈 식별자를 인자로 취하고 모듈 객체를 Promise로 반환하는 함수와 동일하다.
node main.js ko // 실행 시 인자를 건네주면 된다.
import fs from 'fs';
const originalReadFile = fs.readFile;
let mockResponse = null;
function mockedReadFile (path, cb) {
setImmediate(() => {
cb(null, mockedResponse)
})
}
export function mockEnable(responseWith) {
mockedResponse = responseWith;
fs.readFile = mockedReadFile;
}
export function mockDisable() {
fs.readFile = originalReadFile;
}
import fs from 'fs';
import { mockEnable, mockDisable } from './mock-read-file.js';
mockEnable(Buffer.from('Hello World'));
fs.readFile('fake-path', (err, data) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log(data.toString());
})
mockDisable();
ESM 환경에서 몽키 패치는 복잡하고 신뢰하기 어렵기 때문에 jest 같은 프레임워크를 사용한다.
import fs, { readFileSync } from 'fs';
import { syncBuiltinESMExports } from 'module';
fs.readFileSync = () => Buffer.from('Hello, ESM');
syncBuiltinESMExports();
console.log(fs.readFileSync === readFileSync);
module의 syncBuiltinESMExports를 이용하여 default exports 객체에 있는 속성들의 값이,
named exports와 동일한 것으로 매핑되게 할 수 있다.
strict mode에서 실행된다.
참조 유실 ( strict mode로 인한 )
require, export, module.exports, filename, dirname 등 몇 가지 참조가 정의되지 않는다.
대신에 import.meta에서 데이터를 꺼낼 수 있다.
import.meta.url은 현재 모듈을 참조한다.
문맥 상 require()도 허용할 수 있다.
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
ES에서의 this는 undefined, CommonJS에서의 this는 exports이다.
ESM은 default exports에 한하여 CommonJS를 import 할 수 있다.
JSON을 CommonJS처럼 가져올 수는 없다.
ES 모듈의 또 다른 기본적인 특성은 임포트된 모듈이 익스포트된 값에 대해 읽기 전용 라이브 바인딩된다는 개념입니다.
// count.js
export let count = 0;
export function increment() {
count++;
}
// main.js
import { count, increment } from './counter.js';
console.log(count); // 0
increment();
console.log(count); // 1
count++; // TypeError : Assignment to constant variavble!
이러한 특성을 읽기 전용 라이브 바인딩 ( readonly binding ) 이라고 한다.
문제는 모듈에서는 이러한 변화를 알지 못할 것이라는 점이다.