지난 글에서 ESM 모듈에서 CommonJS 모듈을 import하는 방법을 알아봤다면(아무 문제 없이 할 수 있었습니다) 이번에는 CommonJS 모듈에서 ESM 모듈을 require해보겠습니다. 과연 지난 번처럼 잘 될까요? 다음 세 파일을 준비합니다.
package.json
...
"type": "commonjs",
...
esm.mjs
export const c = 'd';
export default {
a: 'b',
c,
};
cjs.js
const a = require('./esm.mjs');
const { c } = require('./esm.mjs');
console.log(a);
console.log(c);
node cjs로 코드를 실행해보면 다음과 같은 에러가 발생합니다.
node:internal/modules/cjs/loader:1117
throw new ERR_REQUIRE_ESM(filename, true);
^
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/zerocho/esm.mjs not supported.
Instead change the require of /Users/zerocho/esm.mjs to a dynamic import() which is available in all CommonJS modules.
at Object.<anonymous> (/Users/zerocho/cjs.js:1:11) {
code: 'ERR_REQUIRE_ESM'
}
CommonJS에서 ESM 모듈을 require하려고 하니 에러가 발생하는 것입니다. 해결 방법은 에러 메시지에 나와 있습니다. dynamic import()로 바꾸라고 하네요.
cjs.js를 다음과 같이 수정합니다.
import('./esm.mjs').then((module) => {
console.log(module);
});
import()는 프로미스인지라 then의 결괏값으로 모듈을 가져옵니다. 여러 ESM 모듈을 동시에 불러오려면 Promise.all을 해야할 수도 있습니다.
node cjs로 파일을 실행해보면 정상적으로 불러옵니다.
[Module: null prototype] { c: 'd', default: { a: 'b', c: 'd' } }
한 가지 특이한 점은, export default 했던 것은 default라는 키 아래에 데이터가 들어있다는 점입니다. 한 뎁스 들어가야 해서 번거롭긴 하지만 이렇게 하는 것이 최선입니다.
그런데 이렇게 해도 타입스크립트에서는 ESM 모듈 import 시 TS2307: Cannot find module 패키지명 or its corresponding type declarations. 에러가 발생하는 경우가 있습니다. 그럴 때는 이 게시글 을 참고하세요!