LHJ

I'm a FE developer.

프론트엔드 개발환경의 이해 - 웹팩

21 Sep 2020 » node_webpack2

프론트엔드 개발환경의 이해 - 웹팩 (기본)

배경 (웹팩이 필요한 이유)

먼저 모듈에 대해 이야기 해보자.
문법 수준에서 모듈을 지원하기 시작한 것은 ES2015부터다.
import/export 구문이 없었던 모듈 이전 상황을 살펴보는 것이 웹팩 등장 배경을 설명하는데 수월할 것 같다.

아래 덧셈 함수를 보자.
과거 사용방식을 예로 보여주겠다.

// math.js
function sum (a, b) {
    return a + b; // 전역 공간에 sum이 노출
}
// app.js
sum(1, 2); // 3
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<script src="src/math.js"></script>
<script src="src/app.js"></script>
</body>
</html>

위 코드는 모두 하나의 HTML 파일 안에서 로딩해야만 실행된다.
math.js가 로딩되면 app.js는 이름 공간(name space)에서 ‘sum’을 찾은 뒤 이 함수를 실행한다.
문제는 ‘sum’이 전역 공간에 노출된다는 것.
전역 스코프가 오염되는 현상이 발생한다.
다른 파일에서도 ‘sum’이란 이름을 사용한다면 충돌한다.

런타임 에러가 발생할 우려가 굉장히 커지는 것이다.

IIFE 방식의 모듈

이러한 문제를 예방하기 위해 스코프를 사용한다.
함수 스코프를 만들어 외부에서 안으로 접근하지 못하도록 공간을 격리하는 것이다.
스코프 안에서는 자신만의 이름 공간이 존재하므로 스코프 외부와 이름 충돌을 막을 수 있다.

// math.js
var math = math || {}; // math 네임스페이스

(function () {
    function sum (a, b) {
        return a + b;
    }
    math.sum = sum; // 네임스페이스에 추가
})()
console.log(math.sum(1, 2));

같은 코드를 즉시실행함수로 감싸서 다른 파일에서 이 안으로 접근할 수가 없다.
심지어 같은 파일일지라도 말이다.
자바스크립트 함수 스코프의 특징이다.
sum이란 이름은 즉시실행 함수 안에 감추어졌기 때문에 외부에서는 같은 이름을 사용해도 괜찮다.
전역에 등록한 math라는 이름공간만 잘 활용하면 된다.

즉시실행함수표현(IIFE, Immediately Invoked Function Expression)**은 정의되자마자 즉시 실행되는 Javascript Function을 말한다.

다양한 모듈 스펙

이러한 방식으로 자바스크립트 모듈을 구현하는 대표적인 명세가 AMD와 CommonJS이다.

CommonJS는 자바스크립트를 사용하는 모든 환경에서 모듈을 하는 것이 목표다.
exports 키워드로 모듈을 만들고 require() 함수로 불러들이는 방식이다.
대표적으로 서버 사이드 플랫폼인 Nodejs에서 이를 사용한다.

// math.js
exports function sum (a, b) {
    return a + b;
}
// app.js
const sum = require('./math.js');
sum(1, 2); // 3

AMD(Asynchronous Module Definition)는 비동기로 로딩되는 환경에서 모듈을 사용하는 것이 목표다.
주로 브라우저 환경이다.

UMD(Universal Module Definition)는 AMD 기반으로 CommonJS 방식까지 지원하는 통합 형태다.

이렇게 각 커뮤니티에서 각자의 스펙을 제안하다가 ES2015에서 표준 모듈 시스템을 내놓았다.
지금은 바벨과 웹팩을 이용해 모듈 시스템을 사용하는 것이 일반적이다.
ES2015 모듈 시스템의 모습을 살펴보자.

// math.js
export function sum (a, b) {
    return a + b;
}
// app.js
import * as math from './math.js';
math.sum(1, 2); // 3

export 구문으로 모듈을 만들고 import 구문으로 가져올 수 있다.

브라우저 모듈 지원

안타깝게도 위의 ES2015+ 모듈 시스템은 모든 브라우저에서 지원하지는 않는다.
인터넷 익스플로러를 포함한 몇몇 브라우저에서는 여전히 모듈을 사용하지 못한다.
가장 많이 사용하는 크롬 브라우저만 잠시 살펴보자.
(버전 61부터 모듈시스템을 지원한다.)

// math.js
export function sum (a, b) {
    return a + b;
}
// app.js
import * as math from './math.js';
math.sum(1, 2); // 3
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<script type="module" src="src/app.js"></script>
</body>
</html>

script 태그로 로딩할 때 type=”text/javascript” 대신 type=”module”을 사용한다.
app.js는 모듈을 사용할 수 있다.

그러나 브라우저에 무관하게 모듈을 사용하고 싶다…
이제야 웹팩이 나올 차례다.

Tip

현재 폴더를 가벼운 로컬 서버로 만들어주는 명령어

npx lite-server