[모던자바스크립트] 모듈 정리

박재윤·2021년 1월 11일
0

자바스크립트

목록 보기
11/11

어플리케이션의 크기가 커져 파일을 분리했을 때 분리된 각각의 파일을 모듈이라고 부른다.

모듈은 대개 클래스 하나 또는 같은 목적을 가진 여러개의 함수로 구성된다.

스크립트의 크기가 점차 커지자 자바스크립트 커뮤니티는 다음과 같은 모듈을 만들었다.

  • AMD – 가장 오래된 모듈 시스템 중 하나로 require.js라는 라이브러리를 통해 처음 개발됨
  • CommonJS – Node.js 서버를 위해 만들어진 모듈 시스템.
  • UMD – AMD와 CommonJS와 같은 다양한 모듈 시스템을 함께 사용하기 위해 만들어졌다.

모듈이란?

모듈은 파일 하나에 불과하다.

export, import를 사용해서 다른 모듈을 불러올 수 있다.

// 📁 sayHi.js
export function sayHi(user) {
  alert(`Hello, ${user}!`);
}
// 📁 main.js
import {sayHi} from './sayHi.js';

alert(sayHi); // 함수
sayHi('John'); // Hello, John!

브라우저에서 모듈은 <script type="module"> 속성을 사용해서 스크립트가 모듈이라는 것을 브라우저가 알 수 있도록 해야한다.

모듈의 특징

1. 엄격모드로 실행

모듈은 항상 엄격 모드로 실행된다.

2. 모듈 레벨 스코프

모듈은 자신만의 스코프가 있다. 외부에서 사용하게 하려면 export를 사용한 뒤 사용하려는 곳에서 import를 해야한다.

3. 단 한 번만 실행된다.

동일한 모듈이 여러곳에서 사용되더라도 모듈은 최초 호출 시 단 한 번만 실행이 되고 실행 결과는 모듈을 가져가려는 모든 모듈에 export된다.

// 📁 alert.js
alert("모듈이 평가되었습니다!");
// 동일한 모듈을 여러 모듈에서 가져오기

// 📁 1.js
import `./alert.js`; // 얼럿창에 '모듈이 평가되었습니다!'가 출력됩니다.

// 📁 2.js
import `./alert.js`; // 아무 일도 발생하지 않습니다.

이러한 특징 때문에 모듈 설정을 쉽게 할 수 있다. 최초로 실행되는 모듈의 객체 프로퍼티를 원하는대로 설정하면 다른 모듈에서 이 설정을 그대로 사용할 수 있기 때문이다.

4. import.meta

import.meta 객체는 현재 모듈에 대한 정보를 제공한다.

브라우저 환경에서는 스크립트의 url 정보를 얻을 수 있다.

5. this

모듈 최상위 레벨의 this는 undefined이다.

모듈이 아닌 일반 스크립트의 this는 전역객체인 것과 대조된다.

<script>
  alert(this); // window
</script>

<script type="module">
  alert(this); // undefined
</script>

6. 지연 실행

브라우저 환경에서 모듈 스크립트는 항상 지연 실행된다. 외부 스크립트, 인라인 스크립트와 관계 없이 마치 defer 속성을 붙인 것 처럼 실행된다.

defer, async 스크립트

브라우저는 HTML을 읽다가 <script>...</script> 태그를 만나면 스크립트를 먼저 실행해야 하기 때문에 DOM 생성을 멈춘다. 이런 동작 방식은 두 가지의 문제를 만든다.

  1. 스크립트에서 스크립트 아래에 있는 DOM 요소에 접근할 수 없다.
  2. 페이지 위쪽에 용량이 큰 스크립트가 있는 경우 스크립트가 페이지를 막는다.

이런 문제를 해결하기 위해서 script 태그를 페이지의 맨 마지막에 넣는 방법이 있다. 그런데 HTML 문서 자체가 매우 큰 경우는 페이지가 매우 느려질 가능성이 있다.

이런 상황에서 defer, async를 사용할 수 있다.

defer

defer는 스크립트를 백그라운드에서 다운로드 한다. 따라서 스크립트를 다운로드 하는 중에도 HTML 파싱을 멈추지 않는다. 그리고 스크립트는 페이지 구성이 완료되면 실행이 된다. 스크립트가 DOM에 의존하고 있다면 defer가 유용하다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/249d789d-c7f9-472b-8e7c-0b5bcdd89273/Untitled.png

async

async는 defer와 마찬가지로 페이지와 독립적으로 동작한다. async 스크립트는 다운로드가 되기를 기다리지 않고 페이지 내 콘텐츠를 처리한다. 이후에 스크립트의 실행 중에는 HTML 파싱을 멈춘다.

async 스크립트들은 서로를 기다리지 않고 다운로드가 된다. 그리고 다운로드가 완료된 순서대로 실행이 된다. 따라서 다른 스크립트에 종속적이지 않은 스크립트를 실행할 때 유용하다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/afa0de4c-6185-4193-a76a-76cab0738cc1/Untitled.png

7. 브라우저에서 경로가 없는 모듈을 허용하지 않는다.

브라우저 환경에서는 import는 반드시 url 앞에 와야한다.

import {sayHi} from 'sayHi'; // Error!
// './sayHi.js'와 같이 경로 정보를 지정해 주어야 합니다.

모듈 내보내고 가져오기

export와 import의 다양한 활용법

1. 선언부 앞에 export 붙이기

// 배열 내보내기
export let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

// 상수 내보내기
export const MODULES_BECAME_STANDARD_YEAR = 2015;

// 클래스 내보내기
export class User {
  constructor(name) {
    this.name = name;
  }
}

2. 선언부와 떨어진 곳에서 export 붙이기

// 📁 say.js
function sayHi(user) {
  alert(`Hello, ${user}!`);
}

function sayBye(user) {
  alert(`Bye, ${user}!`);
}

export {sayHi, sayBye}; // 두 함수를 내보냄

3. 전부 다 가져오기(*)

// 📁 main.js
import * as say from './say.js';

say.sayHi('John');
say.sayBye('John');

하지만 이렇게 하는 것보다 가져올 것을 구체적으로 명시하는 것이 좋다.

  • 성능면에서 좋고
  • 더 간결하게 쓸 수 있고
  • 어떤 것을 쓰는지 명확하게 표현할 수 있기 때문에 리팩토링, 유지보수에 좋다.

4. as로 이름을 바꿔 가져오기, 내보내기

// 📁 main.js
import {sayHi as hi, sayBye as bye} from './say.js';

hi('John'); // Hello, John!
bye('John'); // Bye, John!
// 📁 say.js
...
export {sayHi as hi, sayBye as bye};

5. export default

export default를 사용하면 해당 모듈에 개체가 하나만 있다는 것을 명확히 나타낸다.

// 📁 user.js
export default class User { // export 옆에 'default'를 추가해보았습니다.
  constructor(name) {
    this.name = name;
  }
}

6. 모듈 다시 내보내기

export ... from ... 문법을 사용하면 가져온 개체를 즉시 ‘다시 내보내기(re-export)’ 할 수 있다.

npm 패키지를 만들었을 때 유용하게 사용할 수 있다.

동적으로 모듈 가져오기

import 표현식

import(module) 표현식은 모듈을 읽어서 모듈이 내보내는 것을 모두 포함하는 객체를 담은 이행된 프로미스를 반환한다.

let modulePath = prompt("어떤 모듈을 불러오고 싶으세요?");

import(modulePath)
  .then(obj => <모듈 객체>)
  .catch(err => <로딩 에러, e.g. 해당하는 모듈이 없는 경우>)

0개의 댓글