자바스크립트 모듈 시스템

BaeSeong-min·2025년 1월 17일

프론트엔드 지식

목록 보기
7/9
post-thumbnail

📁모듈 시스템 이란?

애플리케이션의 규모가 커지면서 파일을 여러개로 분리한다.
이때, 분리된 파일을 모듈이라고 한다.

정확하게 말하자면,

모듈은 특정 기능을 독립적인 단위로 분리하여 export/import를 통해 재사용할 수 있는 코드 조각이다.

이러한 모듈을 언제든지 불러올 수 있게 하는 방법이 모듈 시스템이다.

현재 활발하게 많이 사용되는 모듈 시스템:

  • ES모듈 시스템 : 프론트엔드 웹 개발 시에 많이 사용함

  • CommonJS : Node.JS 환경에서 사용하는 기본 모듈 시스템

📂모듈을 사용하지 않았을 때의 문제

모듈 시스템이 있기 전에는 script 태그를 사용해서 분리된 파일을 불러왔다.

하지만, 위 방법은 분리된 각각의 파일들이 전역 스코프를 공유하기 때문에 문제가 된다.
전역 스코프를 공유하게 되면, 동일한 변수명으로 인한 의도치 않은 결과가 만들어질 수 있다.

🔽a.js

var number = 10;
console.log("a.js > number: ", number);

🔽b.js

var number = 20;
console.log("b.js > number: ", number);

🔽practice.html

<!DOCTYPE html>
<html lang="ko">
<head>
</head>
<body>
    <script src="a.js"></script>
    <script src="b.js"></script>
    <script>
        console.log('number: ', number);
    </script>
</body>
</html>

b.js 파일을 가장 마지막에 불러왔기 때문에 number 변수값이 20으로 덮어 써진다.

이처럼, a.js 파일과 b.js 파일은 나뉘어져 있어도 실제로 동작할 때는 마치 하나의 파일 안에 있는 것처럼 동작한다. 즉, 전역 스코프를 공유한다.

🔽하나의 파일 안에 있는 것처럼 동작한다는 말의 예시

<script>
  var number = 10;
  // ...
  var number = 20;
  // ...
</script>

모듈은 자신만의 스코프를 가지기 때문에, 전역 스코프에서 발생하는 문제를 해결할 수 있다.

📂모듈 만드는 방법

script 태그에 type="module"을 지정하게 되면, src 속성의 값으로 지정해준 파일은 모듈로 간주가 된다.

이때 만들어진 모듈에는 ES 모듈 시스템이 적용된다. CommonJS 방식으로 작성된 파일은 정상적으로 동작하지 않는다.

<script type="module" src="b.js"></script>

📁모듈 시스템 장점

  • 유지보수 용이: 기능들이 모듈화가 잘 되어 있는 경우, 기능 개선이나 수정에 용이하다.

  • 네임 스페이스화: 코드의 양이 많아질 수록 전역 스코프에 존재하는 변수명이 겹치는 경우가 존재한다. 이때, 모듈로 분리하면 각 모듈은 자신만의 스코프를 갖기에 변수명이 겹치는 문제를 해결할 수 있다.

  • 재사용성: 같은 코드를 반복하지 않고 모듈로 분리시켜서 필요할 때마다 재활용할 수 있다.

📝네임 스페이스화란 변수나 함수의 이름 충돌을 방지하기 위한 방법이다.

예를 들어 A라는 프로그램에는 a, b, c라는 기능이 있다고 가정하자.
이때, B라는 프로그램에도 b와 c 기능이 필요하고 하자.

이 경우 b와 c 기능을 구현한 코드를 반복해서 A, B 모든 프로그램에 적어줄 필요가 없다.
b와 c 기능을 모듈화 시키면 되기 때문이다.

즉, b라는 기능과 c라는 기능을 분리시켜서 필요한 순간에 가져와 사용할 수 있다.

📁ES 모듈 시스템

ES6(ES2015)에 도입된 자바스크립트 모듈 시스템이다.

<script> 태그에 type="module" 속성을 추가해주면, 이 파일은 모듈로서 동작한다.
ES 모듈 시스템이 적용되기에 import, export 같은 구문을 사용한다.

  • export, export default: 외부에서 모듈을 사용할 수 있도록, 모듈을 내보낼 때 사용하는 키워드

  • import: 외부에서 모듈을 불러올 때 사용하는 키워드

ES 모듈: ES 모듈 시스템이 적용되는 모듈

📂ES 모듈 사용 예시

🔽 ./modules/index.js

import * as math from 'math.js';

console.log('perfectScore: ', math.perfectScore);
console.log('sum: ', math.sum);
console.log('avg: ', math.avg);

🔽 ./modules/math.js

export const perfectScore = 100;

export const sum = (num1, num2) => {
    return num1 + num2;
}

export const avg = (num1, num2) => {
    return (num1 + num2) / 2;
}

🔽practice.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="module", src="module/index.js"></script>
</body>
</html>

practice.hmtl 파일에서 모듈로 동작하는 index.js을 불러온다.

index.js 파일에서는 math.js 모듈을 불러온다. 이때, math.js에서 export한 모든 데이터를 math 객체에 저장하고, math 객체에 저장된 변수나 함수 혹은 클래스를 사용한다.

최종적으로 math.js 모듈에서 받아온 데이터를 출력한다.


🔽import 하는 다른 방법
import { perfectScore, sum, avg } from 'math.js';

위와 같은 방법으로 math.js 모듈에서 export 하는 변수나 함수 혹은 클래스를 직접 선언해서 사용할 수도 있다.

📝index.js 파일이 모듈로 불리는 이유는 다른 모듈을 import 하는 파일은 모듈이기 때문이다.

📝math.js가 모듈이라 할 수 있는 이유는, 별도의 모듈 선언 없이도 파일 내에서 export를 사용했기 때문에 모듈로 간주된다.

📂export default

export default는 기본적으로 다른 모듈에서 import할 때 기본적으로 가져갈 수 있는 데이터를 지정해주는 키워드이다.

🔽 ./modules/index.js

import subtract from './math.js';

console.log('sub: ', subtract(80, 90));

🔽 ./modules/math.js

const subtract = (num1, num2) => {
    return num1 - num2;
}

export default subtract;

🔽practice.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="module", src="module\index.js"></script>
</body>
</html>

export default로 내보내진 데이터는

  • import할 때 중괄호 {} 없이 가져올 수 있다.

  • import할 때 이름을 자유롭게 변경 가능하다.

🔽export된 데이터를 다른 이름으로 받는 예시

import subtract2 from './math.js';

🗂️하나의 기본값으로 전달하기

🔽 ./modules/index.js

import math from './math.js'

console.log('perfectScore: ', math.perfectScore);
console.log('sum: ', math.sum(80, 10));
console.log('avg: ', math.avg(80, 90));
console.log('sub: ', math.subtract(80, 90));

🔽 ./modules/math.js

const perfectScore = 100;

const sum = (num1, num2) => {
    return num1 + num2;
}

const avg = (num1, num2) => {
    return (num1 + num2) / 2;
}

const subtract = (num1, num2) => {
    return num1 - num2;
}

export default {
    perfectScore,
    sum,
    avg,
    subtract,
};

🔽practice.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="module", src="module\index.js"></script>
</body>
</html>

각각의 변수에 export 키워드를 붙여도 되지만, 하나의 기본값으로 내보낼 데이터를 한번에 지정할 수 있다.

🗂️" import * as 별칭 "을 사용할 때 주의할 점

  • export default와 함께 사용할 경우

math.js에서 export default로 내보낸 값은 math.default로 접근해야 한다.
import * as math from ./math.jsexport default를 포함하지 않는다.

🔽 ./modules/index.js

import * as math from './math.js';

console.log(math.default(20, 10)); // 10 (default export 함수 호출)

🔽 ./modules/math.js

export default function subtract(num1, num2) {
    return num1 - num2;
}

📁CommonJS 모듈 시스템

Node.JS 환경에서 자바스크립트 모듈을 사용하기 위해 만들어진 모듈 시스템이다. 브라우저에서는 기본적으로 지원되지 않는다.

  • exports, module.exports: 외부에서 모듈을 사용할 수 있도록, 모듈을 내보낼 때 사용하는 키워드

  • require: 외부에서 모듈을 불러올 때 사용하는 키워드

CommonJS 모듈: CommonJS 모듈 시스템이 적용되는 모듈

📂CommonJS 모듈 사용 예시

🔽 ./commonjs/index.js

const {perfectScore, sum, avg, subtract} = require('./math');

console.log('perfectScore: ', perfectScore);
console.log('sum: ', sum(80, 10));
console.log('avg: ', avg(80, 90));
console.log('sub: ', subtract(80, 90));

🔽 ./commonjs/math.js

exports.perfectScore = 100;

exports.sum = (num1, num2) => {
    return num1 + num2;
}

exports.avg = (num1, num2) => {
    return (num1 + num2) / 2;
}

exports.subtract = (num1, num2) => {
    return num1 - num2;
}

exports 키워드를 사용해서 외부로 데이터를 내보낸다.

변수를 선언하는 것과 마찬가지로 const, let, var 키워드를 사용하며, 내보내진 데이터는 require를 통해 불러올 수 있다.

🗂️하나의 객체로 import 하는 방법

const math = require('./math');

console.log('perfectScore: ', math.perfectScore);
console.log('sum: ', math.sum(80, 10));
console.log('avg: ', math.avg(80, 90));
console.log('sub: ', math.subtract(80, 90));

중괄호 {}를 사용하는 전개구문으로 내보내진 값을 받을 수 있다.
뿐만 아니라 math라는 하나의 객체를 사용해서, export된 값을 받을 수 있다.

🗂️하나의 객체로 묶어서 export 하는 방법

🔽 ./commonjs/index.js

const math = require('./math');

console.log('perfectScore: ', math.perfectScore);
console.log('sum: ', math.sum(80, 10));
console.log('avg: ', math.avg(80, 90));
console.log('sub: ', math.subtract(80, 90));

🔽 ./commonjs/math.js

const perfectScore = 100;

const sum = (num1, num2) => {
    return num1 + num2;
}

const avg = (num1, num2) => {
    return (num1 + num2) / 2;
}

const subtract = (num1, num2) => {
    return num1 - num2;
}

module.exports = {
    perfectScore,
    sum,
    avg,
    subtract,
};

📁NodeJS에서 ES 모듈 사용하기

Node.JS 버전 13.2부터 ES모듈 시스템에 대한 정식 지원이 시작됨에 따라 다른 도구 없이 Node.JS 환경에서 손쉽게 ES Module을 사용할 수 있게 되었다.

📂NodeJS에서 ES Module 사용법

  • package.json에 type="module" 선언

Node.JS 환경에서 CommonJS 모듈 시스템이 아니라 ES Module 시스템이 적용된 모듈을 실행시키니까 경고 메세지를 출력한다.

반면 package.json 파일에 type="module"를 선언해주니 경고 메세지 없이 정상적으로 출력이 되는 것을 확인할 수 있다.

📝Node.js는 웹 브라우저가 아니라 컴퓨터(서버)에서 JavaScript 파일을 실행할 수 있도록 만든 런타임 환경이다. 따라서 node 파일명.js 명령을 터미널에서 실행하면 이는 Node.js 환경에서 파일이 실행되는 것이다.

참조

profile
성민의 개발 블로그 🔥

0개의 댓글