아래는 ESM 환경을 이해하기 위한 배경을 설명하고 있습니다
빠른 이해를 원하시는 분은 아래로 쭉 내려가십숑
JavaScript 와 ECMAScript
ES6( ECMAScript 2015 또는 ECMAScript 6)
가 도대체 무엇인가!!! 에 대한 글입니다
ECMA 인터네셔널(Ecma International)
정보 통신에 대한 *표준을 제정하는 비영리 표준화 기구
*표준
CD ROM 볼륨과 파일구조, C# 언어 규격, JSON 포맷처럼 일부 정보 통신 기술에 대한 표준
qwerty키보드 레이아웃 같은 표준(ecma가 만든 건 아니지만)
각각의 표준에는 고유한 이름과 번호를 가지고 있음
그 중에 알아볼 건 ECMA-262임
ECMA-262
인터네셔널에 의해 제정된 하나의 기술 규격으로,
범용 목적의 *스크립트 언어에 대한 명세를 담고 있음
*스크립트 언어(Script Language)
응용 소프트웨어(웹 브라우저,게임 등)를 제어하는 프로그래밍 언어
다른 응용 프로그램에 삽입되어 동작되는 언어임
비스크립트 언어인 C, C++, Java 등은 컴파일 된 후 독립적으로 작동하는 하나의 응용 프로그램이지만,
스크립트 언어인 JavaScript, jQuery, PHP, Python 등은 다른 응용 프로그램 안에 삽입되어 해석됨
+ JavaScript는 HTML문서 내에 삽입되어 사용하는 언어
+ jQuery는 HTML문서에 삽입하여 사용할 수 있는 자바스크립트 라이브러리
+ JSP(JavaServer Pages/자바서버페이지)는 HTML 페이지 안에 Java코드를 직접 삽입하여 사용
+ PHP는 HTML문서 안의 서버 측 스크립트 언어임(리눅스 운영체제에 Apache 웹서버를 설치, MySQL DB 환경에서 주로 사용됨
+ Python은 특정 플랫폼에 의존하지 않고 독립적인 객체지향 스크립트 언어임
응용 프로그램과 독립하여 사용되고, 사용자가 응용 프로그램의 동작을 사용자의 요구에 맞게 수행할 수 있게 해줌
자바스크립트(JavaScript/JS)
Brendan Eich가 1995년 넷스케이프에서 근무하며 개발함
웹 사이트와 어플리케이션을 동적, 상호작용적으로 만들어주는 / 객체(Object) 기반의 스크립트 언어
HTML로 웹의 내용(프레임)을 작성하고
CSS로 웹을 디자인하며,
JavaScript로 웹의 동작을 구현함! > 생동감과 상호 작용을 제공(팝업, 애니메이션, 동영상 등)
넷스케이프는 ECMA인터네셔널에 자바스크립트를 제출했고,
이를 통해 JavaScript 공식사양인 ECMAScript 표준이 만들어졌음!! => ES
JavaScipt 특징)
인터프리터 언어임 > 브라우저에서 직접 실행할 수 있어요!
동적 타이핑, 변수 유형 선언이 불필요함 > 잘못 해석될 여지가 있어 버그와 오류 조심
사용자의 웹브라우저에서 주로 실행 > 서버와 통신하지 않아도 사용자와 상호작용, 입력에 응답, 동적업데이트
=>자바스크립트는 정적인 웹사이트를 더욱 생동감있게 만드는 데 사용되는 객체기반 스크립트 언어이다!


import 쓰고 싶으면 package.json에 "type":"module" 추가하세용
로컬 파일 임포트할 때는 확장자까지 적어야 합니다. 예: import { foo } from './utils.js'
이거 말고도 파일 확장자를 .mjs로 바꾸는 방법도 있어요("type": "module" 없이도 import 가능).
근데 module을 왜 넣어야하는거야?
Node.js는 기본이 CommonJS(require)라서, .js 파일에서 import/export를 쓰려면
“이 프로젝트는 ESM(ECMAScript Module) 쓸 거야”라고 알려줘야 해요.
그 역할을 하는 게 package.json의 "type": "module" 입니다.
왜 필요한가
기본값이 CommonJS라서 .js 파일은 CJS로 취급되고, import 문 쓰면 SyntaxError가 납니다.
ESM 모드 활성화: "type": "module"을 넣으면 .js 파일을 ESM으로 해석해서 import/export, top-level await 등을 사용할 수 있어요.
넣으면 달라지는 점
상대 임포트에 확장자 필요: import { foo } from './utils.js' 처럼 .js/.mjs를 붙여야 합니다.
require, module.exports 사용 불가: 대신 export/import를 사용.
- 꼭 require가 필요하면: import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
__filename, __dirname 없음:
- 대신 이렇게)
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
대안
"type": "module" 안 쓰고 파일 확장자를 .mjs로 바꾸기
아예 ESM 안 쓰고 CommonJS 유지: const express = require('express')
Express, mysql2 같이 CJS 패키지도 ESM에서 import express from 'express'처럼 기본(default) 임포트로 잘 불러올 수 있어요(CJS → ESM 인터롭 지원).
근데 왜 import랑 require는 공존할 수 없어?
let 이나 const는 그냥 쓸 수 있게 해줬으면서,
왜 import는 따로 세팅을 해주거나 require랑 같이 못쓰게 하는거야?
import/export와 require/module.exports는 “문법”만 다른 게 아니라, 동작 방식(로더/해석/평가 순서)이 서로 달라서 한 파일을 동시에 두 모드로 돌릴 수 없어요.
let/const는 JS 엔진이 지원하는 “언어 문법”이라 모듈 시스템과 무관하게 쓸 수 있지만,
import는 “모듈 시스템(ESM)” 전용 문법이라 파일을 모듈 모드로 돌리게 하는 설정이 필요합니다.
왜 같은 파일에서 공존이 안 되나
서로 다른 파서 목표(Grammar goal)
CommonJS(CJS)는 “script goal”로 파싱돼서 import 문법 자체를 허용하지 않음.
ESM은 “module goal”로 파싱돼서 require 같은 CJS 전용 전역이 없음.
노드는 파일을 파싱하기 전에 “이 파일을 CJS로 볼지 ESM으로 볼지”를 먼저 결정해야 해서,
한 파일을 두 모드로 동시에 해석할 수 없어요.
정적 vs 동적
ESM import는 정적 분석 대상(파일 로딩·의존성 그래프를 파싱 시점에 확정) → 트리 셰이킹, 순서 보장, top-level await 가능.
require는 런타임 함수(조건부/동적 로딩 가능, 동기 로딩).
내보내기/가져오기 의미 차이
ESM은 “라이브 바인딩”(값이 변하면 참조가 반영).
CJS는 “값 스냅샷”에 가까움 + 모듈 전체가 단일 객체로 export.
상호 매핑 규칙이 필요해서, ESM→CJS/ CJS→ESM 인터롭을 “규칙”으로 제공하지만 문법을 섞어 쓰게 하진 않음.
로더·해결 규칙과 캐시가 다름
확장자/패키지 경로 해석, 동기/비동기 로딩, 캐시 키 등이 달라 한 파일 내 혼합 시 일관성이 깨짐.
그럼 프로젝트에서 둘 다 못 쓰나? → “파일 단위”로는 한 모드, “프로젝트 단위”로는 공존 가능
같이 쓰는 방법
- ESM 파일에서 CJS 모듈 쓰기 (createRequire)
- ESM 파일(.mjs 또는 "type": "module" 하의 .js)에서:
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
const cjsThing = require('./legacy.cjs')
- ESM 파일(.mjs 또는 "type": "module" 하의 .js)에서:
- CJS 파일에서 ESM 모듈 쓰기 (동적 import)
- CJS 파일(.cjs 또는 "type": "commonjs" 하의 .js)에서:
;(async () => {
const { default: esmThing } = await
import('./modern.mjs')
esmThing() })()
- CJS 파일(.cjs 또는 "type": "commonjs" 하의 .js)에서:
- 파일 확장자로 모드 분리
- .mjs → ESM, .cjs → CJS
package.json에 "type": "module"을 두면 .js는 ESM, .cjs는 CJS로 강제 분리 가능
반대로 "type": "commonjs"면 .js는 CJS, .mjs는 ESM
- .mjs → ESM, .cjs → CJS
왜 let/const는 추가 세팅 없이 됐나
let/const는 V8(자바스크립트 엔진)이 언어 차원에서 지원하는 문법이라, 모듈 시스템 선택과 무관합니다.
반면 import/export는 “모듈 시스템을 사용하겠다”는 선언 그 자체라,
로더/해석 방식 전체를 ESM으로 전환해야 하고, 그래서 파일/프로젝트 레벨의 모드 결정이 필요합니다.
실무 팁
새 코드: ESM(import/export) 권장. package.json에 "type": "module" 또는 .mjs 사용.
기존 CJS 유지 필요: 확장자 .cjs 유지하고, 필요한 곳만 점진적으로 ESM으로 전환(브리지: createRequire / 동적 import).
라이브러리 작성 시: 배포는 dual package 구조(exports 필드로 ESM/CJS 모두 제공) 고려.
"type": "module"을 켜면 이 파일은 ESM 모드가 되고, CommonJS 전용 기능들은 그대로는 못 씁니다.
--
+라이브러리 vs 프레임워크
라이브러리
자주 사용하는 자바스크립트 작업을 쉽게 구현하는 데 사용할 수 있는 미리 작성된 코드 모음
개발 속도가 빨라진다
프레임워크
라이브러리의 모음
프레임워크(도구상자)------------ 웹 사이트 구축을 위한 모든 코드 제공
라이브러리(도구1) 특정기능
라이브러리(도구2) 특정기능
라이브러리(도구3) 특정기능
...
----------------------------------
예)
자바스크립트의 프레임워크
Vue.js
Node.js
Angular
자바스크립트 라이브러리
React
jQuery
엥 나 *뷰는 프레임워크고 리액트는 라이브러리인거 난생처음 알았음
헤에.............뭐임? 나중에 알아봐야함
알아볼거 진짜 개많음 죽음을 줘
*
프레임워크는 코드를 프레임에 맞춰서 개발한다 함
예시로 vue는 파일을 만들 때, .vue라는 형태에 맞게 사용함
.js로도 쓸 수 있지만 효율성이 구림
반면
리액트는 라이브러리임
.jsx 형태로 코드를 작성하는데, 자바스크립트만을 이용해서 구현함
Vue는 html js css 코드 영역을 분리해서 작성함
<templete> 안에는 HTML <script> 안에는 JavaScript <style>안에는 CSS < 이러한 형태임
이러하기 때문에 뷰가 리액트보다 코드 가시성 및 생산성이 좋다고 평가하는 개발자 분들이 많음
=> 걍 뷰알못이라 안 써봄 이슈로 몰랏슴 ㅎㅎ
'STUDY > [ JavaScript ]' 카테고리의 다른 글
| 함수와 모듈 / 함수 호출() 함수 참조, Export Default Import /Export Named Import (0) | 2025.10.02 |
|---|---|
| Async/ Await/ Top-Level Await/ Promise/ Callback/ 동기,비동기 작업 (0) | 2025.10.01 |
| 해시 / Object , new Map(), new Set() (0) | 2025.09.30 |
| JS JSX (0) | 2025.09.28 |
| forEach for of for in nullish ?? 병합연산자 (0) | 2025.09.26 |