require와 exports, module.exports가 각각 import, export, export default로 바뀌었습니다. 상당한 부분에서 차이가 있으므로 단순히 글자만 바꿔서는 제대로 동작하지 않을 수 있습니다. ES 모듈의 import나 export default는 require나 module처럼 함수나 객체가 아니라 문법 그 자체입니다.
파일도 js 대신 mjs 확장자로 변경되었습니다. js 확장자에서 import를 사용하면 SyntaxError: Cannot use import statement outside a module 에러가 발생합니다. mjs 확장자 대신 js 확장자를 사용하면서 ES 모듈을 사용하려면 5장에서 배울 package.json에 type: "module" 속성을 넣으면 됩니다.
CommonJS 모듈과는 다르게 import 시 파일 경로에서 js, mjs 같은 확장자는 생략할 수 없습니다. 또한, 폴더 내부에서 index.js도 생략할 수 없습니다.
표로 두 모듈 형식의 차이를 정리해봤습니다.
▼ 표 3-1 CommonJS 모듈과 ECMAScript 모듈의 차이
차이점 |
CommonJS 모듈 |
ECMAScript 모듈 |
문법 |
require('./a'); module.exports = A; const A = require('./a'); exports.C = D; const E = F; exports.E = E; const { C, E } = require ('./b'); |
import './a.mjs'; export default A; import A from './a.mjs'; export const C = D; const E = F; export { E }; import { C, E } from './b.mjs'; |
확장자 |
js cjs |
js(package.json에 type: "module" 필요) mjs |
확장자 생략 |
가능 |
불가능 |
다이내믹 임포트 |
가능(3.3.3절 참고) |
불가능 |
인덱스(index) 생략 |
가능(require('./folder')) |
불가능(import './folder/index.mjs') |
top level await |
불가능 |
가능 |
__filename, __dirname, require, module.exports, exports |
사용 가능(3.3.4절 참고) |
사용 불가능(__filename 대신 import.meta.url 사용) |
서로 간 호출 |
가능 |
지금까지 CommonJS 모듈과 ES 모듈을 알아봤습니다. 서로 간에 잘 호환되지 않는 케이스가 많으므로 웬만하면 한 가지 형식만 사용하는 것을 권장합니다.