본문으로 건너뛰기
김신건의 로그

[Javascript] ES Modules (import / export)

· 수정 · 📖 약 1분 · 298자/단어 #javascript #modules #esm #fundamentals
JS ES Modules, ESM, import export, ES6 module

정의

ES Modules (ESM) 은 표준 JS 모듈 시스템 (ES6). import / export 키워드. 브라우저와 Node.js 16+ 모두 지원.

export

named export

// utils.js
export const PI = 3.14;
export function add(a, b) { return a + b; }
export class Calculator { ... }

// 일괄 export
const NAME = 'lib';
function foo() {}
export { NAME, foo };

// rename
export { foo as bar };

default export

// math.js
export default function add(a, b) { return a + b; }

// 또는
function add(a, b) { return a + b; }
export default add;

한 파일에 default 1 개, named 여러 개 가능.

import

named import

import { PI, add } from './utils.js';
import { add as plus } from './utils.js';        // rename
import { PI, add, default as Lib } from './lib.js';  // default + named

default import

import add from './math.js';                     // 어떤 이름이든
import myAdd from './math.js';                   // 같음

namespace import

import * as utils from './utils.js';
utils.PI;
utils.add(1, 2);

side-effect only

import './polyfill.js';        // 실행만, export 안 가져옴

재-export

// index.js (barrel pattern)
export { foo } from './foo.js';
export { bar } from './bar.js';
export * from './baz.js';
export { default } from './main.js';

여러 모듈을 한 진입점으로.

dynamic import

const module = await import('./heavy.js');
module.someFunction();

// 또는 then
import('./heavy.js').then(m => m.use());

조건부 / 지연 로딩에 유용. 코드 스플리팅의 핵심.

ESM 의 특징

1. strict mode 자동

// 모든 ESM 은 자동으로 strict
'use strict';   // 불필요

2. top-level await (ES2022)

// ESM 에서만
const data = await fetch('/api/init').then(r => r.json());
export { data };

3. import.meta

console.log(import.meta.url);        // 모듈의 URL
// 브라우저, Node 둘 다

ESM vs CommonJS

항목ESMCommonJS
문법import/exportrequire/module.exports
동기/비동기async (static), top-level await동기
정적 분석✓ (tree-shaking)
호이스팅export 가 호이스팅즉시 평가
브라우저✗ (번들러 필요)
Node 파일 확장자.mjs 또는 "type": "module".cjs 또는 기본

Node.js 에서 ESM 사용

// package.json
{
    "type": "module"
}

또는 파일 확장자 .mjs.

함정

1. import 경로의 확장자

// 브라우저
import { x } from './foo';        // ❌ 확장자 필요
import { x } from './foo.js';     // ✓

// Node ESM
import { x } from './foo.js';     // ✓ (필수)

// 번들러 (Vite, webpack)
import { x } from './foo';        // 알아서 해결

플랫폼별 차이.

2. import 가 호이스팅됨

foo();
import { foo } from './foo.js';    // ✓ 동작 (호이스팅)

3. import 의 immutable binding

import { count } from './module.js';
count = 5;     // ❌ TypeError (immutable)

import 한 변수는 상수 binding. 모듈에서 변경하면 import 한 곳에서도 반영.

4. circular dependency

// a.js
import { b } from './b.js';
export const a = 1;

// b.js
import { a } from './a.js';
export const b = a + 1;       // a 가 아직 정의 전일 수도

순환 import 시 부분 평가된 모듈이 노출. 가능하면 피한다.

5. CJS interop

// Node ESM 에서 CJS import
import lodash from 'lodash';        // default 만 가능
import { merge } from 'lodash';     // ⚠️ 일부 라이브러리는 안 됨

tree-shaking

// 좋은 import (필요한 것만)
import { partition } from 'lodash-es';

// 안 좋음 (전체)
import _ from 'lodash';
_.partition(...);

ESM 만 tree-shaking 가능. CJS 는 정적 분석 어려움.

참고

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기