[TIL] 모듈

동찌·2023년 4월 3일

모듈

모듈은 프로그램에서 코드를 구성하는 작은 단위로, 코드의 재사용성유지 보수성을 높여주는 개념입니다.
모듈은 관련된 함수, 객체, 변수 등을 하나로 묶어서 내보내는 것으로, 다른 파일에서 해당 모듈을 불러와서 사용할 수 있습니다.

모듈을 사용하면 프로그램을 각각의 파일로 구성할 수 있어서, 프로그램 전체가 복잡해지더라도 개발자가 코드를 쉽게 관리할 수 있습니다. 또한, 모듈을 재사용함으로써 반복적인 코드 작성을 피할 수 있으므로, 개발 시간과 노력을 절약할 수 있습니다.


export

모듈을 사용하려면, 다른 파일에서 해당 모듈을 불러오기 위해 내보내는 과정이 필요한데, 현재 모듈에서 정의한 함수, 객체, 변수 등을 다른 파일에서 사용할 수 있도록 내보낼 수 있습니다.

Node.js에서는 module.exports 또는 exports 객체를 사용하여 모듈을 내보냅니다.

JS에서는 export 또는 export default를 사용하여 모듈을 내보냅니다.

export default 구문에서 변수 선언에 var, let, const를 사용할 수 없습니다.

// ex
export default const foo = 'foo' // 사용 불가

이는 해당 모듈의 기본 값을 내보내는 구문이기 때문에 변수 선언 자체는 값이 아니므로 변수를 해당 구문으로 내보내는 것은 의미가 없습니다.

해당 구문에서는 함수, 클래스, 객체, 배열 등의 값들은 모두 내보낼 수 있습니다.


require

require 함수는 Node.js에서 모듈을 로드하는데 사용되는 내장 함수입니다.
require 함수는 모듈을 동기적으로 로드합니다. 즉, 모듈이 로드될 때까지 코드의 실행이 차단됩니다. 이는 모듈 로드가 완료된 후에만 코드가 실행됨을 보장합니다.


import

import는 ES6부터 도입된 모듈 시스템에서 사용되는 구문입니다.
import구문을 사용하여 다른 모듈에서 내보낸 함수, 객체, 변수 등을 불러와 현재 파일에서 사용할 수 있습니다.
import구문은 비동기적으로 처리되며, 로딩된 모듈은 Promise 객체를 반환합니다.

import구문은 브라우저 환경에서 natively supported브라우저 자체에서 해당 기능을 지원하는 것을 의미하지 않습니다.
따라서 bundlertranspiler 등의 도구를 사용해야 합니다. 대표적인 예로 Webpack, Babel, Rollup 등의 도구가 있습니다.
이러한 도구를 사용하면, import구문이 동작하도록 코드를 변환해주기 때문에, 브라우저에서도 import구문을 사용할 수 있습니다.


기술면접 대비 질문

Q. require와 import차이점을 설명해주세요.

  • 문법

    • require
    const module = require('module-name')
    • import
    import module from 'module-name'
  • 동작 방식

    • require
      • 동기적으로 모듈을 로드하기 때문에 require 구문 다음에 오는 코드는 모듈 로딩이 완료될 때까지 실행되지 않습니다.
      • 이러한 특성 때문에, 서버 측에서 자주 사용됩니다.
    • import
      • 비동기적으로 모듈을 로드하기 때문에 import 구문 다음에 오는 코드는 모듈 로딩이 완료되지 않아도 실행됩니다.
      • 이러한 특성 때문에, 클라이언트 측에서도 사용할 수 있습니다.
  • 사용 환경

    • require
      • Node.js와 같은 CommonJS기반의 환경에서 사용됩니다.
    • import
      • ES6 이상의 JavaScript환경에서 사용됩니다.
      • 브라우저에서는 해당 구문을 natively supported하지 않기 때문에, 이를 사용하기 위해서는 transpiler나 bundler 등의 도구를 사용해야 합니다.
  • 불러오는 방식

    • require
      • 해당 모듈 전체를 가져오는 방식으로 동작합니다.
    • import
      • 필요한 특정 부분만 가져오는 방식으로 동작하여, 메모리 효율을 높일 수 있습니다.
  • 내보내는 방식

    • require
      • module.exports를 통해 지정됩니다.
    • import
      • export 키워드를 사용해 지정됩니다.
      • export default 키워드를 사용하면, 해당 모듈의 기본 값을 내보낼 수 있습니다.
  • 재할당 가능성

    • require
      • 불러온 모듈의 내용을 다른 값으로 재할당할 수 있습니다.
    • import
      • 불러온 값이 read-only입니다. 따라서 재할당이 불가능합니다.

Q. 각각 어떤 상황에서 쓸 수 있나요?

모두 JavaScript에서 모듈을 로드하는 구문이지만, 사용하는 상황이 다릅니다.

require 구문은 Node.js에서 주로 사용되며, CommonJS 기반의 환경에서 모듈을 로드하는데 적합합니다.
require 구문은 동기적으로 모듈을 로드하기 때문에, 서버사이드에서 모듈을 로딩할 때 유용합니다.

반면에 import 구문은 클라이언트 사이드에서 주로 사용되며, ES6이상의 환경에서 모듈을 로드하는데 적합합니다. import 구문은 비동기적으로 모듈을 로드하기 때문에, 클라이언트 측에서 모듈을 로딩할 때 유용합니다.

따라서, 기존의 CommonJS기반의 서버 측에서는 require 구문을 사용하고, 클라이언트 측에서는 ES6 이상의 JavaScript환경을 사용하는 경우 import 구문을 사용하는 것이 일반적입니다.


GPT선생님이 알려준 예상 꼬리 질문

1. require와 import를 사용할 때 어떤 장단점이 있나요?

  • require
    • 장점
      • 모듈 로딩이 동기적으로 이루어지므로, 코드가 복잡한 경우 로딩 순서를 파악하기 쉽습니다.
      • 동적인 모듈 로딩이 가능합니다.
    • 단점
      • 모듈 로딩이 동기적으로 이루어지므로, 로딩이 느리거나 장시간 실행되는 경우 전체 애플리케이션의 성능이 저하될 수 있습니다.
      • 브라우저에서는 기본적으로 사용할 수 없으며, CommonJS 기반의 환경에서만 사용할 수 있습니다.
  • import
    • 장점
      • 모듈 로딩이 비동기적으로 이루어지므로, 전체 애플리케이션의 성능이 향상될 수 있습니다.
      • 정적인 모듈 로딩이 가능합니다.
      • 트리 쉐이킹(Tree Shaking) 기능을 지원하여, 사용하지 않는 코드를 제거할 수 있습니다.
    • 단점
      • 코드가 복잡한 경우 로딩 순서를 파악하기 어렵습니다.
      • 동적인 모듈 로딩이 불가능합니다.

2. Node.js에서는 CommonJS를, 브라우저에서는 ES6 모듈을 사용하도록 권장합니다. 그 이유는 무엇인가요?

Node.js에서는 CommonJS를, 브라우저에서는 ES6 모듈을 사용하도록 권장하는 이유는 각각의 환경에서 가장 적합한 모듈 시스템을 사용하기 위해서입니다. Node.js는 서버 사이드 개발을 위한 환경이기 때문에, 동기적인 모듈 로딩이 가능한 CommonJS가 더 적합합니다. 반면, 브라우저에서는 비동기적인 모듈 로딩이 필요하기 때문에 ES6 모듈이 더 적합합니다.

3. ES6 모듈을 사용하는 경우, 모듈 로딩이 동기적으로 이루어지지 않습니다. 이것이 의미하는 것은 무엇인가요? 이것이 어떤 상황에서 유용할까요?

ES6 모듈에서 모듈 로딩이 동기적으로 이루어지지 않는 것은, 모듈 로딩 시점과 모듈 실행 시점이 다르다는 것을 의미합니다. 이것은 모듈 로딩이 필요할 때만 로딩되므로, 전체 애플리케이션의 성능이 향상될 수 있습니다. 또한, 모듈간의 의존성을 사전에 파악하여 최적화할 수 있도록 하는 트리 쉐이킹(Tree Shaking) 기능을 가능하게 합니다.

4. ES6 모듈에서는 정적 모듈 로딩이 가능합니다. 이것이 어떤 의미인가요? 이것이 어떤 상황에서 유용할까요?

ES6 모듈에서의 정적 모듈 로딩이란, import 문이 소스 코드의 상단에 위치하며, 런타임 시점에서 모듈을 로드하는 것이 아니라 빌드 시점에서 모듈을 미리 로드하는 것을 말합니다. 이는 모듈 로드 시점이 예측 가능해지므로, 모듈 의존성 관리와 코드 번들링 등에서 매우 유용합니다.
또한, 정적 모듈 로딩은 특정한 모듈만 로드하도록 할 수 있기 때문에, 필요한 모듈만 로드하여 메모리 사용량을 줄일 수 있습니다. 이는 대규모 웹 애플리케이션의 경우 특히 중요합니다.

5. ES6 모듈은 실행 시점의 상태를 공유하지 않습니다. 이것이 의미하는 것은 무엇인가요? 이것이 어떤 상황에서 유용할까요?

ES6 모듈에서 실행 시점의 상태를 공유하지 않는다는 것은, 모듈 내에서 선언된 변수나 함수 등의 상태가 해당 모듈 내에서만 유효하고, 다른 모듈에서 접근할 수 없다는 것을 의미합니다. 이는 모듈 간 의존성이 명확하게 분리되어 있으므로, 모듈 간의 상호작용이 명확하게 정의되고 예측 가능해지므로 애플리케이션의 전체적인 안정성과 유지 보수성을 향상시킵니다.
또한, ES6 모듈에서는 최초 로드된 모듈이 메모리 상에 캐시되므로, 같은 모듈을 다시 로드할 필요가 없습니다. 이는 전체 애플리케이션의 성능을 향상시키는 데 도움이 됩니다.


몰랐던 것

트리쉐이킹(Tree Shaking)

JavaScript에서 불필요한 코드를 제거하는 최적화 기술입니다.
트리쉐이킹은 트리쉐이킹은 주로 모듈 시스템과 함께 사용되며, 사용하지 않는 코드를 정적 분석하여 제거합니다.

  • 예시
// moduleA.js
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

// moduleB.js
import { add } from './moduleA.js';

console.log(add(1, 2));

이 때, 트리쉐이킹을 적용하면 add() 함수만 포함된 번들 파일이 생성됩니다.
이처럼 분석된 코드 중에서, 실행되지 않을 것으로 예측되는 코드는 번들링하지 않기 때문에 파일 크기를 줄이고 실행 속도를 높이는 것이 가능해집니다.


출처

모던 자바스크립트 Deep Dive - 48장 모듈
chat GPT

0개의 댓글