이번 리액트 수업시간 때, 모듈 파일을 내보내고 불러오는 과정에서 확실히 이해하지 못한 것 같아 이 글을 작성하게 되었습니다.

📌 모듈이란?

모듈이란, 개발을 하면서 애플리케이션이 방대해짐에 따라 파일을 분리해야할 경우가 발생한다. 이 때 분리된 파일을 모듈이라고 한다.

시간이 지나 모듈이 웹 표준에 등재되면서 브라우저와 Node.js 환경에서 모듈을 사용할 수 있게 되었다.

모듈 특징

  • 모듈파일을 사용하기 위해서는 import 해온 script 파일에 type 속성이 module로 설정되어 있어야한다.
1
<script type="module" src="index.js"></script>
  • 모듈 스코프를 가진다.
  • Strict mode
  • 지연 실행된다(defer) -> 스크립트의 상대적인 순서가 유지될 수 있는 이유
  • 확장자를 꼭 적어줘야한다.

모듈은 단독적으로 사용하는 경우는 드물고 주로 웹팩(Webpack)이라는 번들러를 사용하여 모듈을 한번에 묶어 서버에 올리는 방식을 사용한다.

웹팩에 대해서는 새로운 게시물에서 다뤄보도록 하고 이제 모듈을 불러오고 내보내는 방법에 대해 알아보자.

CommonJS vs ES6 방식

1. CommonJS

  • require : 가져오기 위한 키워드
1
2
// index.js
const sayHi = require("./sayHi.js");
  • exports : 내보내기 위한 키워드
1
2
3
4
// sayHi.js
const foo = () => console.log("sayHi~!");

module.exports = foo;

2. ES6 방식

  • import : 가져오기 위한 키워드
1
2
// index.js
import foo from "./sayHi.js";
  • export
1
2
3
4
// sayHi.js
const foo = () => console.log("sayHi~!");

export default foo;

둘의 차이에 대해 알아두고 앞으로는 ES6 문법을 사용할 것이니 이에 대해서 자세히 알아보자.

export

모듈을 내보내는 방식은 다양하다.

  1. 선언부에서 내보내기
1
export const name = "loco";
  • 단, 함수나 클래스를 내보내기할 경우에는 ; (세미콜론)을 붙이지 않아야 한다.
  1. 선언부와 떨어진 곳에서 내보내기
1
2
3
const name = 'loco';

export name;

만약 여러개를 내보내고 싶다면 객체로 감싸서 내보내기 해야한다.

1
2
3
4
5
6
7
8
9
10
// say.js
const sayHi = (name) => {
console.log(`Hi~ ${name}!`);
};

const sayBye = (name) => {
console.log(`Bye~ ${name}!`);
};

export { sayHi, sayBye };

import

1
2
3
4
5
// main.js
import { sayHi, sayBye } from "./say.js";

sayHi("John"); // Hi~ John!
sayBye("selly"); // Bye~ selly!

export 할 때, 객체형태로 감싸서 내보내기를 하였으면 불러올 때도 객체형태로 감싸 이름 그대로 가져와야한다.

하지만 가져와야할 함수나 변수가 100만개라면? 일일히 언제 써주기가 힘드니 이럴 경우 * (에스터리스트)를 사용하여 모두 가져오기하여 객체처럼 사용할 수 있다.

1
2
3
4
5
// main.js
import * as greeting from "./say.js";

greeting.sayHi("Yong"); // Hi~ Yong!
greeting.sayBye("Jin"); // Bye~ Jin!

하지만 이런 경우는 드물고, 대게 어떤 대상을 가져오는지를 구체적으로 하는 것 명시하는 것이 좋다.

왜냐하면 웹팩을 사용하면 로딩속도를 높이기 위해 최적화를 하게되는데 이 경우 사용하지 않는 리소스는 삭제되기 때문이다.

import as

as를 사용하여 이름을 바꿔서 가져올 수 있다. export 에서도 가능하지만 주로 import 에서만 사용하는 것이 명시적이다.

1
2
3
4
5
// main.js
import { sayHi as hi, sayBye as bye } from "./say.js";

hi("John"); // Hi~ John!
bye("John"); // Bye~ John!

export default

모듈은 크게 2가지 종류로 나뉘게 된다.

  1. 위 처럼 say라는 함수들이 다수있는 라이브러리 형태의 모듈
  2. 개체 하나만 선언된 모듈

유틸 함수들을 내보내는 경우가 아니라면 주로 2번의 경우를 선호한다.

해당 모듈에 개체가 1개만 있다는 것을 명시적으로 구분하기 위해 export default 키워드를 사용한다.

1
2
3
import validation from "./validation.js";

const isValid = validation();
  • export default로 내보내기한 경우에 가져오기할 때는 중괄호{}가 필요없고 원하는 이름으로 가져올 수 있다.
  • 또한, 개체 한개만 내보낸 것을 가져오기 때문에 export default로 내보낼 때는 식별자나 이름없이 내보낼 수 있다.

🔥 [22.11.09 추가]

❗️ component 폴더의 index.js 모아서 다시 내보내기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// components/ToggleButton/ToggleButton.js
export function ToggleButton() {
return <button></button>;
}

// components/index.js
export * from "./Demo";
export * from "./ToggleButton";
export * from "./A11yHidden";
export * from "./Banner";

// app/App.jsx
import { ToggleButton } from "components";
export default function App() {
<div className="App">
<ToggleButton />
</div>;
}
  • ToggleButton 컴포넌트를 이름 내보내기 해주고 있다.
  • 위와 같이 components 폴더의 index.js파일에 여러 컴포넌트를 다시 내보내기로 보내줄 때, 만약 ToggleButton 컴포넌트를 기본 내보내기를 해주었다면 아래처럼 index.js에서 다시내보내기 해줄 때, {}로 감싸고 default로 받은 객체를 이름으로 설정해주고 내보내줘야한다.
1
export { default as ToggleButton } from './ToggleButton";

왜냐하면, ToggleButton 이외의 다른 컴포넌트들도 default로 내보냈기 때문에 구분을 하기 위해서 다시 내보내기 할 때, 이름을 설정해줘야한다.

이러한 불편함 때문에 이름 내보내기를 사용한다.

❗️ 화살표 함수로 내보내기시 주의사항

1
2
3
export default ({ onText, offText, on, onToggle, activeClass }) => {
return <button>...</button>;
};
  • 위와 같이 화살표 함수로 한줄로 작성하여 익명함수로 내보내고 App.jsx에서 이름을 정하여 받아서 사용하더라도 브라우저 환경에서 컴포넌트 구조를 확인하면 컴포넌트 이름이 Annonymous라고 뜬다.

🏓 소감

수업시간에 모듈을 기본 내보내기, 이름 내보내기를 사용하면서 둘의 차이가 무엇인지? 그리고 CommonJS와 ES6에서 모듈을 불러오고 내보내는 방식의 차이에 대해 확실히 알고 가는 시간이여서 한층 성장하였다고 느낀다.