Native JSON Modules — 번들러 없이 JSON을 import하는 시대
Import Attributes와 함께 표준이 된 native JSON module. 어떻게 동작하고, 기존 번들러 방식과 뭐가 다른지 정리했다.
번들러가 항상 필요했던 이유
JavaScript에서 JSON 파일을 쓰려면 오래전부터 번들러가 필요했다. import config from './config.json'이 동작하는 건 webpack이나 Vite가 JSON을 JavaScript 모듈로 변환해줬기 때문이다. 브라우저 네이티브로는 안 됐다.
이제 그게 바뀌었다. 모던 브라우저와 Node.js, Deno, Bun이 네이티브 JSON 모듈을 지원하기 시작했다. 번들러 없이 import만으로 JSON을 다룰 수 있다.
문법: with { type: "json" }
// 정적 import
import config from './config.json' with { type: 'json' }
// 동적 import
const data = await import('./data.json', {
with: { type: 'json' }
})핵심은 with { type: 'json' } 절이다. 런타임에게 "이 파일을 JavaScript 코드가 아니라 데이터로 파싱하라"고 명시적으로 알려주는 계약이다. 비유하면 배송 박스에 '깨지기 쉬운 물품' 스티커를 붙이는 것과 같다. 내용물이 뭔지 처리 방법을 박스 바깥에서 명시하는 거다.
[💡 잠깐! 이 용어는?]
Import Attributes: import 구문에 메타데이터를 추가하는 문법. with { type: '...' }로 모듈 타입을 명시한다. 이전에는 assert 키워드를 썼지만 with으로 표준화됐다.
기존 번들러 방식과 뭐가 다른가
| 항목 | 번들러 방식 | Native JSON Modules |
|---|---|---|
| 처리 시점 | 빌드 타임 | 런타임 |
| 브라우저 ESM 지원 | 불필요 (번들 결과물) | 네이티브 지원 |
| 빌드 스텝 필요 여부 | 필수 | 불필요 |
| 번들에 인라인 | 보통 됨 | 기본적으로 안 됨 |
| 캐싱 | 번들 파일 기준 | HTTP 캐싱 + 모듈 캐싱 |
번들러 방식에서 JSON은 대부분 빌드 결과물에 인라인된다. Native JSON Modules는 별도 파일로 서빙되고, ES 모듈처럼 파싱 한 번 후 캐싱된다. 여러 파일에서 같은 JSON을 import해도 같은 인스턴스를 공유한다.
왜 with { type: 'json' }이 필요한가
확장자만으로는 파일 타입을 신뢰할 수 없다. .json 파일이 실제로는 악의적인 JavaScript를 담을 수 있다. CORS와 보안 정책이 개입하면 확장자 기반 추측은 더 복잡해진다.
with { type: 'json' }은 "이 파일을 코드로 실행하지 말고 데이터로만 처리하라"는 명시적 지시다. 브라우저와 런타임이 MIME 타입이나 Content-Type과 무관하게 일관되게 처리할 수 있다.
포인트: "import attributes는 파일 타입을 추측하는 대신, import하는 코드가 기대하는 것을 선언하는 패턴이다." — JSON 너머 CSS modules 등 미래 모듈 타입으로 확장 가능한 설계다.
실제 사용 사례
import messages from './ko.json' with { type: 'json' }
export function t(key) {
return messages[key] ?? key
}// 동적 로딩: 언어 파일을 lazy하게 가져올 때
async function loadLocale(lang) {
const messages = await import(`./locales/${lang}.json`, {
with: { type: 'json' }
})
return messages.default
}[💡 잠깐! 이 용어는?] ES 모듈 캐싱: 같은 URL의 모듈은 한 번만 파싱하고 이후 요청에서는 캐싱된 결과를 반환하는 메커니즘. 여러 파일에서 동일한 JSON을 import해도 파싱이 중복되지 않는다.
브라우저 지원
Chrome, Firefox, Safari 최신 버전과 Node.js 22+, Deno, Bun이 지원한다. import() 동적 방식과 정적 import 모두 동작한다.
번들러를 완전히 대체하는 건 아니다. 프로덕션에서 번들링이 필요한 이유(트리 쉐이킹, 코드 스플리팅, 폴리필)는 여전히 존재한다. 다만 JSON 파일 하나를 위해 번들러 설정을 추가해야 하는 상황은 줄어든다. 비유하면 대형 공사 현장에서 인부가 여전히 필요하지만, 나사 하나 조이려고 굳이 공사팀 전체를 부르지 않아도 되는 것과 같다.
마무리
Native JSON Modules는 작은 변화처럼 보이지만 의미가 있다. 웹 플랫폼이 JSON을 first-class 모듈로 다루기 시작했다는 신호이기 때문이다. with { type: 'json' } 문법은 앞으로 CSS modules 등으로 확장될 Import Attributes 표준의 첫 번째 실용적 사례다. 번들러 없는 간단한 프로젝트나 엣지 함수에서는 바로 써볼 수 있다.
참고:
같은 카테고리 · JavaScript
비슷한 주제의 최신 글
태그가 겹치는 글
공통 태그가 많을수록 위에 보인다