Module

모듈이란 단지 하나의 파일에 불과합니다. 하나의 스크립트는 하나의 모듈입니다. 모듈에 import, export 키워드를 사용해서 스크립트(모듈) 끼리 기능공유가 가능해집니다.

우리가 자바스크립트를 작성하는 과정에 있어서 구식 방법으로서는 모든 스크립트를 하나의 큰 스크립트로 작성하거나 작은 스크립트로 나눠서 로드를 했습니다.

하지만 이제는 그렇게 하지 않습니다. 큰 스크립트를 여러 모듈을 이용해서 나눠 코드의 재사용률을 높입니다. 이러한 모듈로서는 npm node 모듈 패키지 관리자들을 통해서 다른 사람들이 올려놓은 여러 라이브러리 즉, 모듈들을 무료로 다운받아서 사용할 수도 있습니다.

Bundling

이렇게 여기저기서 가져온 모듈들을 크게 하나의 파일로 만듭니다. 이과정을 번들링이라고 합니다. 이과정에서 쓰지 않은 Dead 코드들도 걸러냅니다.

Babel

이과정을 거친후에 이전의 브라우저에서도 자바스크립트 파일이 돌아갈수 있도록 (자바스크립트 파일을 ES5 버전으로 번역합니다.) BABEL 이라는 것으로 번역과 동시에 폴리필을 채웁니다.

번들링과 Babel 과정을 망라해서 빌드 과정이라고 하는데 이빌드 과정을 webpack 혹은 PARCEL 이라는 프로그램으로 빌드합니다.

빌드 이후에는 실제 브라우저에서 돌아갈 Production 으로서의 자바스크립트 번들 파일이 나오게 됩니다.

Build Tool

위 에서와 같이 빌드과정을 진행시켜주는 빌드 툴에는 웹팩과 PARCEL등이 있습니다. 이러한 빌드 툴이 하는 과정은 다음과 같습니다.

  • html에서 주요 모듈로 사용할 스크립트(진입점)를 정하고 이 스크립트에 대해서 다른 모듈간의 의존관계를 정리합니다. 이러한 모듈을 한데 모아 큰 파일로 만듭니다.
  • 코드의 최적화가 이루어집니다.
    • 도달 가능하지 않는 코드는 삭제됩니다.
    • 내보내진 모듈중 쓰임새가 없는 모듈을 삭제합니다. 가지치기(tree-shacking)
    • console, debugger과 같은 개발관련 코드를 삭제합니다.
    • Babel을 이용해서 모던 자바스크립트를 (ES6+) 를 ES5로 변환합니다.
    • 공백제거, 변수이름 줄이기 등으로 산출물의 크기를 줄입니다.

type='module'

모듈은 <script type='module'> 이라고 속성을 설정해 줘야합니다. 브라우작 스크립트가 모듈이란 것을 인식을 해야 모듈로서의 기능을 할 수 있습니다.

❗️ 로컬에서 html을 열때 브라우저로 열게 되는데 file://, 프로토콜로 열게되면 import,export 지시자가 작동하지 않습니다. 반드시 https, http 프로토콜을 이용해야합니다. 따라서 live-serverstatic-server 를 이용해서 파일을 로드해야합니다.

module로서의 스크립트는 아래와 같은 특징을 갖습니다.

  • 엄격모드로 실행됩니다.
  • 모듈 레벨의 스코프
  • 같은 import, export의 경우 한번만 읽습니다.
  • src 속성이 같은 스크립트는 한번만 읽습니다.
  • defer 속성이 있는 것처럼 스크립트가 로드됩니다.
  • 외부 사이트와 같이 다른 오리진에서 스크립트를 불러올 경우 해당 사이트에서 CORS를 허용해야합니다.
<!-- another-site.com이 Access-Control-Allow-Origin을 지원해야만 외부 모듈을 불러올 수 있습니다.-->
<!-- 그렇지 않으면 스크립트는 실행되지 않습니다.-->
<script type="module" src="http://another-site.com/their.js"></script>
  • 구식 브라우저는 type='module'을 해석하지 못합니다. 따라서 같은 스크립트를 nomodule 속성을 넣어 한번더 스크립트를 삽입합니다.
<script type="module">
  alert("모던 브라우저를 사용하고 계시군요.");
</script>

<script nomodule>
  alert("type=module을 해석할 수 있는 브라우저는 nomodule 타입의 스크립트는 넘어갑니다. 따라서 이 alert 문은 실행되지 않습니다.")
  alert("오래된 브라우저를 사용하고 있다면 type=module이 붙은 스크립트는 무시됩니다. 대신 이 alert 문이 실행됩니다.");
</script>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <!-- <script type="module" defer src="script.js"></script> -->
    <!-- <script defer src="script.js"></script> -->
    <script type="module" defer src="script.js"></script>

    <title>Modern JavaScript Development: Modules and Tooling</title>
    <style>
      body {
        height: 100vh;
        display: flex;
        align-items: center;
        background: linear-gradient(to top left, #28b487, #7dd56f);
      }
      h1 {
        font-family: sans-serif;
        font-size: 50px;
        line-height: 1.3;
        width: 100%;
        padding: 30px;
        text-align: center;
        color: white;
      }
    </style>
  </head>
  <body>
    <h1>Modern JavaScript Development: Modules and Tooling</h1>
  </body>
</html>

import, export

모던 자바스크립트에서 모듈을 가져오는 것과 내보내는 것은 각각 import export 키워드를 이용해서 가능합니다.

// <script type='module' src='./shoppingCart.js'>
const shippingCost = 10;
export const cart = [];

export const addToCart = function (product, quantity) {
  cart.push({ product, quantity });
  console.log(`${quantity} ${product} added to cart`);
};

const totalPrice = 237;
const totalQuantity = 23;

export { totalPrice, totalQuantity as tq };

export default function (product, quantity) {
  cart.push({ product, quantity });
  console.log(`${quantity} ${product} added to cart`);
}
// <script type='module' src='./index.js'>
import * as ShoppingCart from './shoppingCart.js';
ShoppingCart.addToCart('bread', 5);
console.log(ShoppingCart.totalPrice);

import default as CartInfo from './shoppingCart.js';

import add, { addToCart, totalPrice as price, tq } from './shoppingCart.js';
console.log(price);

위 코드에서 ./shoppingCart.js에서 export 를 할때에는 객체로서 해당 코드를 담아 내보냅니다. 따라서 객체를 씌워서 내보낼수 있으며 as 라는 키워드로 바깥으로 내보낼때 이름을 바꿔서 내보낼수도 있습니다.

export에는 default 라는 키워드가 있습니다. 하나의 모듈에 default는 하나만 쓰일 수 있으며 이 default 키워드를 씌우면 내보낼때 객체로 내보내지 않아도 됩니다. 이때 한 모듈당 default 하나만 잇으므로 export 한 모듈에서 가져올 객체의 대상은 정해져있습니다. 따라서 default 가 붙은 객체에는 이름이 없어도 됩니다.

import로서 export에서 코드를 객체로 가져왔으니 객체 비구조화 할당으로 {}를 씌워서 해당 기능을 가져올수 있습니다. 또한 export시 default로 가져온 코드는 중괄호 없이 가져와 사용할 수있습니다.

import 에서도 as가 사용가능합니다. 이때 as는 가져온 기능의 이름을 해당 모듈에서 이름을 바꿔서 사용한다는 의미입니다. import에서 default를 가져온다면 default가 export시 이름이 없어도 됩니다.

❗️ 그리고 다른 모듈에서 가져온 기능들을 또다시 내보낼수도 있습니다. 이러한 과정을 통해 모듈의 캡슐화가 가능합니다.

profile
일상을 기록하는 삶을 사는 개발자 ✒️ #front_end 💻

0개의 댓글