require
와 import
는 JavaScript와 TypeScript에서 모듈을 가져오는 데 사용되는 두 가지 주요 방법입니다. 이 두 방법은 모듈 시스템과 환경에 따라 동작 방식과 특징이 달라지며, 각각의 장단점과 사용 사례가 있습니다. 이번 글에서는 require
와 import
의 차이를 상세히 비교하고 어떤 상황에서 어떤 방식을 사용해야 하는지 알아보겠습니다.
1. 기본적인 개념
require
require
는 CommonJS 모듈 시스템의 일부이며, Node.js 환경에서 주로 사용됩니다.- 동기적으로 모듈을 로드합니다. 이는 코드가
require
문을 만나면 해당 모듈의 로딩이 완료될 때까지 다음 코드의 실행을 멈추고 기다린다는 의미입니다. 예를 들어:require
문을 만납니다.- 요청된 모듈을 찾고 로드합니다.
- 모듈의 코드를 실행합니다.
- 모듈의
exports
객체를 반환합니다. - 이후의 코드를 계속 실행합니다.
이러한 동기적 로딩 방식은 코드의 실행 순서를 예측하기 쉽게 만들지만, 대규모 애플리케이션에서는 성능 저하를 일으킬 수 있습니다.
- 예시:
const fs = require("fs");
const data = fs.readFileSync("/path/to/file");
console.log(data.toString());
import
import
는 ES6(ECMAScript 2015) 모듈 시스템의 일부이며, 브라우저 환경과 최신 JavaScript 및 TypeScript에서 주로 사용됩니다.- 비동기적으로 모듈을 로드합니다. 이는 모듈의 로딩이 백그라운드에서 이루어지며, 다른 코드의 실행을 차단하지 않는다는 의미입니다.
- 호이스팅(hoisting)됩니다. 이는
import
문이 파일의 최상단으로 끌어올려져 실행된다는 뜻입니다. 따라서import
문은 항상 모듈의 시작 부분에 위치하게 됩니다. - 정적 분석이 가능합니다. 컴파일 시점에 모듈 의존성을 파악할 수 있어, 코드 최적화와 에러 검출에 유리합니다.
- 모듈 로딩 순서가 보장됩니다. 순환 의존성 문제를 더 잘 처리할 수 있습니다.
- 트리 쉐이킹(Tree Shaking)을 지원합니다. 사용하지 않는 코드를 제거하여 번들 크기를 줄일 수 있습니다.
- 예시:
import fs from "fs"; const data = fs.readFileSync("/path/to/file"); console.log(data.toString());
2. 주요 차이점
특징 | require |
import |
---|---|---|
모듈 시스템 | CommonJS | ES Module |
사용 환경 | Node.js (주로) | 최신 브라우저, Node.js (ECMAscript 모듈 지원) |
로드 방식 | 동기적 (Synchronous) | 비동기적 (Asynchronous) |
모듈 호출 시점 | 런타임(Run-time) | 컴파일 타임(Compile-time) |
호이스팅 지원 | 지원하지 않음 | 지원 (항상 스코프의 최상단에 위치) |
전체 모듈 가져오기 | require(module) 전체 |
import * as module from 형식 가능 |
부분 가져오기 | const {method} = require(module) |
import { method } from module |
3. 동작 방식의 차이
동기 vs 비동기
require
는 동기적으로 모듈을 로드합니다. 즉,require
호출이 끝날 때까지 다음 코드가 실행되지 않습니다. 이는 I/O를 포함하는 경우 속도가 느려질 수 있다는 단점이 있습니다.import
는 비동기적으로 모듈을 로드하여 성능 최적화에 유리합니다. 브라우저나 번들러가 모듈을 미리 분석하기 때문에 코드 실행을 더 빠르게 할 수 있습니다.
런타임 vs 컴파일 타임
require
는 런타임에 평가되므로, 조건부로 모듈을 가져올 수 있습니다.if (condition) { const module = require("some-module"); }
import
는 컴파일 타임에 정적으로 분석됩니다. 따라서 조건문 내에서 사용할 수 없습니다.
4. 브라우저 환경과 Node.js 환경에서의 차이
- 브라우저에서는 ES 모듈을 지원하기 시작했으며,
import
가 기본적으로 사용됩니다. 반면require
는 Node.js의 CommonJS 모듈 시스템에 의존하기 때문에 브라우저에서는 직접 사용할 수 없습니다. - Node.js에서는
require
를 전통적으로 사용하지만, ES 모듈을 지원하는 최신 버전에서는import
도 사용할 수 있습니다. 이때package.json
파일에"type": "module"
을 설정해야 합니다.
5. ES 모듈의 특징과 CommonJS 모듈과의 차이
ES 모듈
- 정적 구조: 모듈의 구조가 정적이기 때문에, 코드가 로드되기 전에 전체 모듈의 구조를 알 수 있습니다. 이를 통해 최적화가 가능하며, dead code 제거(tree-shaking)에 유리합니다.
Dead code(데드 코드)란 프로그램에서 실행되지 않거나 사용되지 않는 코드를 의미합니다. 이는 불필요한 메모리를 차지하고 프로그램의 크기를 증가시키며, 성능에 부정적인 영향을 줄 수 있습니다. Dead code의 예시로는 다음과 같은 것들이 있습니다:
- 호출되지 않는 함수
- 사용되지 않는 변수
- 도달할 수 없는 코드 (예: return 문 이후의 코드)
- 조건이 항상 false인 if 문 내부의 코드
Tree-shaking은 ES 모듈의 정적 구조를 활용하여 사용되지 않는 코드를 제거하는 최적화 기술입니다. 이를 통해 번들 크기를 줄이고 애플리케이션의 로딩 속도를 향상시킬 수 있습니다. Tree-shaking은 주로 Webpack, Rollup과 같은 모던 번들러에서 지원됩니다.
- 엄격한 모드(strict mode): 모든 ES 모듈은 기본적으로 엄격 모드로 실행됩니다.
- import는 블록 스코프를 따릅니다.
CommonJS 모듈
- 동적 구조: 런타임에 모듈을 가져올 수 있습니다. 이는 동적으로 모듈을 가져오는 상황에서 유리합니다. 예를 들어:
- 조건부 모듈 로딩: 특정 조건에 따라 다른 모듈을 로드해야 할 때 유용합니다.
- 플러그인 시스템: 사용자가 선택한 플러그인을 동적으로 로드할 수 있습니다.
- 성능 최적화: 필요한 시점에 모듈을 로드하여 초기 로딩 시간을 줄일 수 있습니다.
- 에러 처리: 모듈 로딩 실패 시 대체 모듈을 로드하거나 에러를 처리할 수 있습니다.
- 국제화: 사용자의 언어 설정에 따라 다른 언어 모듈을 동적으로 로드할 수 있습니다.
이러한 유연성은 복잡한 애플리케이션에서 특히 유용할 수 있습니다.
- CommonJS 모듈은 strict mode가 기본 적용되지 않습니다.
6. require와 import의 상호 호환성
Node.js에서 require
와 import
를 함께 사용하려면 몇 가지 사항을 고려해야 합니다.
require
에서import
모듈을 사용하려면 ES 모듈이default
export를 갖고 있어야 합니다.// someModule.js export default function () { console.log("Hello from ES module"); } // CommonJS 환경 const someModule = require("./someModule").default; someModule();
- 반대로,
import
에서require
를 사용할 때는import
가 CommonJS 모듈을 기본적으로default
import로 처리하기 때문에 호환성을 위한 추가 조치가 필요할 수 있습니다.
7. 실전 활용 예시
1) TypeScript에서의 사용
TypeScript는 기본적으로 ES 모듈을 따르며, import
를 권장합니다. 하지만 Node.js 환경에서 CommonJS 모듈을 가져와야 하는 경우, esModuleInterop
을 true
로 설정하여 더 편리하게 사용할 수 있습니다.
tsconfig.json
{ "compilerOptions": {
"esModuleInterop": true
}
}
2) 번들러 환경에서의 사용
Webpack, Rollup, Parcel 등의 번들러는 ES 모듈을 권장하며, import
를 통해 모듈을 가져올 때 더 나은 최적화 효과를 얻을 수 있습니다.
8. 어떤 것을 사용해야 할까?
- Node.js 프로젝트: 모듈 시스템의 종류에 따라 결정됩니다. 대부분의 경우 최신 프로젝트에서는
import
를 사용하는 것이 좋지만, 기존 프로젝트나 CommonJS 모듈과의 호환성이 필요한 경우require
를 사용합니다. - 브라우저 환경: 반드시
import
를 사용해야 합니다. 최신 브라우저는 ES 모듈을 네이티브로 지원합니다.
결론
require
는 Node.js의 CommonJS 모듈 시스템에서,import
는 ES6의 모듈 시스템에서 사용되는 방법입니다.require
는 동기적이고 런타임에 모듈을 로드하는 반면,import
는 비동기적이며 컴파일 타임에 로드됩니다.import
는 최신 JavaScript 프로젝트와 브라우저 환경에서 권장되며,require
는 주로 Node.js 환경에서 사용됩니다.
두 방법 모두 각자의 장단점이 있으므로, 프로젝트의 환경과 요구 사항에 따라 적절하게 선택해야 합니다.
'JavaScript & TypeScript' 카테고리의 다른 글
JavaScript 모듈 시스템: export와 export default의 차이점 및 사용법 (0) | 2024.11.12 |
---|---|
Volta - 프로젝트 별 node 관리 (0) | 2024.11.11 |
JavaScript 변수 선언의 모든 것: var, let, const의 차이점과 올바른 사용법 (1) | 2024.10.29 |
비동기 처리: 콜백, 프로미스, 그리고 async/await (TypeScript) (0) | 2024.10.22 |
JavaScript의 내장함수 - every() (0) | 2024.10.12 |