JavaScript 모듈

우영제·2021년 10월 16일
2
post-thumbnail

안녕하세요!


오늘은 쓸 때는 아주 쉽지만, 내가 만들거나 배포할 때는 어려운

모듈 개념에 대해 알아보겠습니다.


JS 모듈이란?

개발을 하다보면 자연스럽게 파일을 여러 개로 분리하게 되는데요,

이때 각각 분리된 파일을 모듈 이라고 부릅니다.


모듈의 형태


  1. 하나의 클래스
  2. 복수개의 함수로 구성된 라이브러리

모듈은 파일 단위로 주로 정의되기 때문에 주로 둘 중 하나의 형태를 띄게 되죠.


JS 모듈의 발전 과정


ES2015(ES6) 이전까지는 모듈에 대한 표준 문법이 없었습니다. 😥


즉, 2015년 이전까지는 우리가 편리하게 사용하던 import, export 문을

사용할 수 없었다는 것이죠!


그럼 이전에 대형 어플리케이션은 어떻게 개발을 했던 걸까요...?

당연히 이런 문제들을 해결하기 위해 표준이 아닌 여러가지 방법들이 제시 됐습니다.


이전에 사용했던 모듈 방식들

  1. commonJS 방식
  2. AMD 방식
  3. UMD 방식

위와 같은 방식들은

webpack등의 설정 파일이나 예전에 작성된 라이브러리에서 상당히 자주 보이지만,

실제 모듈을 개발하고 배포할 때 이제는 잘 사용하지 않는 방식들이 돼버린 거 같습니다.


왜냐면 이젠, 표준이 등장했기 때문이죠!


표준 방식의 모듈 사용법

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

// 📁 main.js
import { sayHi } from './sayHi.js'; // 모듈 import

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

프론트엔드 개발을 해보신 분이라면 위와 같은 형태로 사용하셨을텐데요,

저 문법이 바로 ES6부터 추가된 모듈 방식입니다!


브라우저에서 모듈의 동작 방식


브라우저에서 특정 스크립트를 모듈처럼 동작하게 하려면,
script type="module" 속성을 설정해 모듈이란 걸 브라우저에게 알려줘야합니다.


밑에 예시로 함께 보시죠!


📄 html 예시

<!doctype html>
<script type="module">
  import { sayHi } from './greeting.js';
  document.body.innerHTML = sayHi('John');
</script>

주의사항

🔔 모듈은 로컬 파일에서 동작하지 않고, HTTP 또는 HTTPS 프로토콜을 통해서만 동작합니다.

잉 이것은 무슨 말일까요??


만약 개발중에 webpack-dev-server나 다른 서버를 이용하지 않고,

로컬에서 file:// 프로토콜을 사용해 html을 열어서 테스트 중이었다면

import, export 문법을 사용하실 수 없습니다!


예전에 입사 사전 과제를 작성할 때 이 부분을 몰라서

콘솔창에 계속 export 문법을 알 수 없다는 에러를 해결하지 못해

결국 사용하지 못했던 경험이 있는데요..


아무튼 import/export 지시자는 ✨반드시! http / https 프로토콜을 통해서

테스트해봐야 한다는 것을 기억하셨으면 좋겠습니다.

JS 모듈 기능의 핵심


이 부분이 오늘 포스팅의 가장 맛있는 부분🍔이라고 할 수 있겠는데요,

그 기능을 하나씩 차근차근 알아보겠습니다!


1. strict mode 실행

모듈은 기본적으로 strict mode 로 동작한다

strict 모드에 대해 들어보셨을 겁니다.

use strict

라는 키워드를 통해 스크립트를 strict 모드로 동작시킬 수 있는데요.


이 키워드를 넣지 않으면 sloppy 모드라고 해서 (정식 명칭은 아님)

기본적으로 느슨한(sloppy) 모드로 동작합니다.


strict 모드와 sloppy 모드의 차이점에 대해서는 나중에 따로 정리할 예정이지만,

궁금하신 분들은 strict mode 란 이 글을 참조하시면 좋을 거 같아요!


아무쪼록 모듈은 strict mode로 실행된다는 사실! 꼭 인지하셨으면 좋겠습니다.

2. module level scope

두 번째로 module은 자신만의 scope을 가집니다.

상당히 중요한 특성인데요!

이러한 특성을 가지기 때문에 모듈끼리 변수나 함수의 이름이 겹칠 염려를 하지 않아도 됩니다.


이 특성을 모르시는 분들이 자신의 모듈을 정의할 때

TypeScript의 namespace를 사용하여 모듈마다 namespace를 추가하시는 경우를 봤는데요!


모듈은 이미 자신만의 scope에서 동작하기 때문에,

1번 모듈에서는 2번 모듈 내부에서 정의한 변수에 직접 접근할 수 없다는 사실!

꼭 기억하셨으면 좋겠습니다.


3. import 횟수 최적화

동일한 모듈이 여러 번 import 되더라도, 실제 실행을 최초 한 번만 이루어집니다.

혹시 C/C++ 언어를 사용해봤거나,

import/export에 대해 심도있게 생각해보셨던 분들은 한 번쯤 이런 생각을 하셨을 수도 있습니다.


"혹시 import 할 때마다 내 모듈이 실행되는 것은 아닐까?"


동작 원리에 따르면 지극히 정상적인 생각이지만,

실제로 그렇게 동작하게 되면 상당히 비효율적이기 때문에 모듈 시스템이 내부적으로

최초 딱 한 번만 실행하도록 하고 그 결과를 캐싱했다가 다시 사용하는 형태로 동작하고 있습니다!


C/C++ 에서는 '#pragma once'라는 전처리 명령어를 통해

헤더 파일을 중복해서 include 하지 않을 것을 명시해주고 있는데요!


JS의 모듈 시스템은 그러한 비효율성을 알아서 똑똑하게 처리해준다는 사실! 😲

알고 계시면 좋을 거 같습니다.

요약

🍓 자 그래서 오늘의 포스팅을 요약하자면!


  1. ES6부터 표준 모듈 문법이 생김
  2. 모듈은 암묵적으로 strict mode로 동작
  3. 모듈은 자신만의 scope을 가짐
  4. import를 여러 번 하더라도 실제 실행은 한 번만 이루어짐

입니다.

그동안 내부 원리는 잘 모르고 사용했던 module 개념인데

정리하다보니 생각보다 많은 역할을 해주고 있었네요.


이런 내부적인 동작 특성들을 이해하고,

더 좋은 코드들을 생산해내는 개발자가 되어야겠습니다!

profile
Front-end Developer

0개의 댓글