JavaScript 모듈 시스템

CommonJS, ES Modules, AMD의 차이점과 번들러가 처리하는 과정을 학습합니다

모듈 시스템 선택

모듈 구조

main.js

// ES Modules
import { process } from './utils.js';
import { fetchData } from './api.js';

function main() {
  const data = fetchData();
  const result = process(data);
  console.log(result);
}

export default main;

Import/Export 문법 비교

Export 문법

CommonJS
단일 내보내기
module.exports = myFunction;
여러 내보내기
module.exports = { func1, func2 };
개별 추가
exports.myFunc = myFunction;
ESM
기본 내보내기
export default myFunction;
명명된 내보내기
export { func1, func2 };
인라인 내보내기
export const myFunc = () => {};
AMD
객체 반환
return { func1, func2 };
함수 반환
return myFunction;
의존성과 함께
define(['dep'], function(dep) { return {}; });

Import 문법

CommonJS
전체 가져오기
const module = require('./module');
구조 분해
const { func1, func2 } = require('./module');
조건부 가져오기
if (condition) require('./module');
ESM
기본 가져오기
import module from './module.js';
명명된 가져오기
import { func1, func2 } from './module.js';
동적 가져오기
const module = await import('./module.js');
AMD
의존성 정의
require(['module'], function(module) {});
설정과 함께
requirejs.config({ paths: {} });
조건부 로드
require(['module'], callback, errorCallback);

동적 Import

ES Modules (권장)

// 조건부 로딩
if (condition) {
  const module = await import('./heavy-module.js');
  module.doSomething();
}

// 지연 로딩
button.addEventListener('click', async () => {
  const { Modal } = await import('./modal.js');
  new Modal().show();
});

// 경로 동적 결정
const locale = getUserLocale();
const messages = await import(`./i18n/${locale}.js`);

번들러 최적화

Code Splitting

동적 import는 번들러가 코드를 분할하는 지점이 됩니다.

  • • Webpack: 자동으로 청크 생성
  • • Vite: ES 모듈 기반 최적화
  • • Rollup: 수동 청크 설정 가능

순환 참조 (Circular Dependencies)

moduleA.js

// moduleA.js
import { b } from './moduleB.js';
console.log('moduleA loading');
export const a = 'A';
console.log('moduleB.b:', b); // ReferenceError!

moduleB.js

// moduleB.js
import { a } from './moduleA.js';
console.log('moduleB loading');
export const b = 'B';
console.log('moduleA.a:', a);

⚠️ 순환 참조 문제

  • • CommonJS: 부분적으로 내보낸 객체 반환 (undefined 가능)
  • • ES Modules: ReferenceError 발생 가능
  • • AMD: 의존성 해결 실패

해결책: 의존성 구조 재설계, 지연 로딩, 또는 의존성 주입 패턴 사용

모듈 시스템 상세 비교

특징CommonJSES ModulesAMD
로딩 방식동기적비동기적비동기적
주 사용처Node.js브라우저 & Node.js브라우저 (레거시)
Tree Shaking❌ 불가능✅ 가능❌ 불가능
정적 분석△ 제한적✅ 가능△ 제한적
순환 참조부분 지원에러 발생처리 어려움
브라우저 지원번들러 필요모던 브라우저라이브러리 필요

CommonJS → ES Modules 마이그레이션

❌ Before (CommonJS)

const fs = require('fs');
const { readFile } = require('fs/promises');

class MyClass {
  // ...
}

module.exports = MyClass;
module.exports.helper = () => {};

✅ After (ES Modules)

import fs from 'fs';
import { readFile } from 'fs/promises';

export default class MyClass {
  // ...
}

export const helper = () => {};

💡 마이그레이션 팁

  • • package.json에 "type": "module" 추가
  • • .js 확장자를 명시적으로 포함
  • • __dirname, __filename 대신 import.meta.url 사용
  • • require() 대신 동적 import() 사용
🧑‍💻

1nnovator 김민성

JavaScript 학습 센터 개발자

기술 블로그Interactive JavaScript Learning Platform

🌟 이 프로젝트가 도움이 되셨다면 블로그에서 더 많은 개발 이야기를 확인해보세요!

🤖이 페이지는 생성형 AI의 도움을 받아 제작되었습니다.