자바스크립트에서 모듈 내보내기(export)와 다시 내보내기(re-exporting)

모듈(Module)

- 기능 단위로 분리한 코드 조각

- 캡슐화

- script에서 type=module을 쓴다면, 자동으로 strict mode가 적용된다 (즉 모듈만의 스코프를 만들게 된다)

export는 모듈에서 명시적으로 외부에 공개하는 식별자에 사용하는 키워드이다
import는 export한 값들을 자신의 모듈 스코프로 가져오는 것을 의미한다

 

named export (이름이 있는 내보내기)

named export는 하나의 모듈에서 여러값을 내보낼 때 사용한다

그렇기 때문에 각각의 이름으로 export 하고,

import 시 {중괄호}를 사용해서 export한 이름을 그대로 사용해야 가져와야 한다 

만약 다른 이름으로 가져오려면 as 를 사용해서 재정의 한다

 

그러니 익명으로 export가 안된다

 

export는 2가지로 사용 가능하다

    1. 변수, 함수, 클래스 등 선언할 때 맨 앞에 export 키워드 

    2. 선언부 이외에서는 export {내보낼 값들} 

// 변수 
export const name = 'John Doe';
export const age = 30;

// 함수
export function add(a, b) {
  return a + b;
}

// 클래스
export class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`Hi, I'm ${this.name} and I'm ${this.age} years old.`);
  }
}

// 또는 선언부 이외에서 export
export {name, age, add, Person};


// 재정의 후 import
import { name as personName, age as personAge } from './exampleModule.js'; //

 

export default (기본 내보내기)

모듈에서 단 하나(default)의 값만 기본적으로 내보낼 때 사용한다.

보통 하나의 파일에서 하나의 default export가 좋다

export default function(user) { // 익명 함수 export
  alert(`Hello, ${user}!`);
}

import greet from './greet.js'; // import 시, 임의의 이름으로 가능
greet('John');

 

🌟 여기서 default 키워드는 기본 내보내기를 참조하는 용도로 사용된다

기본 내보내기 = export default로 단일 값을 내보내는 방법
function sayHi(user) {
  alert(`Hello, ${user}!`);
}

export {sayHi as default}; // === export default sayHi

 

default export는 import 시 원하는 대로 이름을 지어 가져올 수 있다

하지만 이렇게 되면 혼란의 여지가 있기 때문에 보통 파일 이름과 동일한 이름을 사용한다

// 마음대로 이름 지어도 동작
import User from './user.js'; 
import MyUser from './user.js'; 

// 일반적인 컨벤션
import User from './user.js';
import LoginForm from './loginForm.js';
import func from '/path/to/func.js';

 

⭐️ 다시 내보내기(re-exporting) == import + export

다시 내보내기는 특정 모듈에서 다른 모듈을 가져와(import) 다시 내보내는 것이다(export)

이 과정을 통해 여러 모듈을 단일 진입점(entry point)에서 내보낼 수 있다

 

다음의 폴더 구조에서

src/
├── components/
│   ├── subcomponents/
│      ├── Greeting.js
│      └── index.js
└── main.js

 

먼저 Greeting.js 모듈이 있다

// src/components/subcomponents/Greeting.js

export default function Greeting(){
  return (
    <div>
      <h1>Hello from Greeting component!</h1>
    </div>
  );
};

 

그리고 모듈의 진입점인 index.js에서 해당 모듈을 다시 내보낸다

// src/components/subcomponents/index.js

// Greeting 컴포넌트를 기본 내보내기
export { default } from './Greeting';

// re-exporting을 풀어보면
import Greeting from './Greeting';
export default Greeting

 

그럼 실제 Greeting 모듈을 사용하는 main.js에서는

// src/main.js

import { Greeting } from './components/subcomponents';

function App() {
    return (
        <>
            <Greeting />
        </>
    );
}

export default App;

 

 

다른 예로는 아래와 같은 파일 구조에서 

- mathUtils, stringUtils는 각각의 함수를 정의하고 내보낸다 (export)

- utils의 중간 모듈에서 mathUtils, stringUtils에서 내보내진 함수를 재정의 해서 다시 내보낸다 (re-exporting)

- main에서 utils를 import 해서 사용한다

/src
  ├── mathUtils.js
  ├── stringUtils.js
  ├── utils.js
  └── main.js

 

1. 개별 모듈 (mathUtils, stringUtils)

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

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


// stringUtils.js
export function capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
}

export function lowercase(str) {
    return str.toLowerCase();
}

 

2. 중개 모듈 (utils)

// utils.js
export { add, subtract } from './mathUtils.js';
export { capitalize, lowercase } from './stringUtils.js';

 

3. 최종 모듈 (main)

// main.js
import { add, subtract, capitalize, lowercase } from './utils.js';

console.log(add(2, 3));           // 출력: 5
console.log(subtract(5, 2));      // 출력: 3
console.log(capitalize('hello')); // 출력: Hello
console.log(lowercase('WORLD'));  // 출력: world

 

 

결론

- 모듈은 기능 단위로 분리 가능한 코드 조각

- named export 는 하나의 파일에서 여러 개를 export 할 수 있고, export한 이름으로 중괄호를 사용해 import 해야한다

- default export 는 하나의 파일에서 단일 export 이므로, 이름 상관없이 Import 할 수 있다

- re-exporting은 다른 모듈에서 이미 내보내진 값을 다시 내보내는 것으로, 모듈 간의 의존성을 관리하고 코드 구조를 단순화하여 가독성과 유지보수성을 향상시키는 방법이다