Webpack

Webpack - Webpack이란?

shin96bc 2024. 3. 10. 20:37

❓ Webpack은 왜 필요한가?

먼저 문법 수준에서 모듈을 지원하기 시작한 것은 ES2015부터입니다.

 

import/export 구문이 없었던 모듈 이전 상황을 살펴보는 것이 webpack 등장 배경을 설명하는데 용이할 것 같습니다.

 

1️⃣ 최초로 사용한 방식

먼저 아래의 두가지 js 파일이 있다고 가정합니다.

 

math.js

// 두개의 숫자를 인자값으로 받아서 더하는 함수
function sum (a, b) {
	return a + b;
}

 

app.js

// math.js 파일의 sum 함수를 사용하는 js 파일
console.log(sum(1, 2));

 

위의 코드들은 모두 하나의 HTML 파일 안에서 로딩해야만 실행됩니다. math.js가 로딩되면 app.js는 이름 공간에서 ‘sum’을 찾은 후 이 함수를 실행합니다.

<html>
	<head>
		...
		<title>Title</title>
	</head>
	<body>
		<script src="src/math.js"></script>
		<script src="src/app.js"></script>
	</body>
</html>

 

 

문제는 ‘sum’이 전역 공간에 노출된다는 것입니다.(전역 스코프가 오염됨) 만약 다른 파일에서도 ‘sum’이라는 이름을 사용한다면 충돌이 발생합니다.

 

또한 ‘sum’이라는 함수는 math.js안에서만 유효한게 아니라, 이 애플리케이션이 돌아가는 어떤 곳에서도 접근할 수 있기 때문에(window 객체에 ‘sum’이 등록된 상태) 누군가 임의로 ‘sum’이라는 이름에 1이라는 값을 할당하게 되면 그 다음 ‘sum(1, 2)’을 호출했을 때 런타임 에러가 발생하게 됩니다.

 

이렇게 전역 스코프가 오염되게 되면 애플리케이션을 예측할 수 없게 되어서 많은 사이드 이펙트가 발생할 수 있습니다.

 

2️⃣ IIFE 방식의 모듈

IIFE란?

  • IIFE: 즉시 실행 함수 표현(Immediately Invoked Function Expression)
  • IIFE는 정의되자마자 즉시 실행되는 Javascript Function을 말합니다.
  • 예시
(function () {
	...
	// 함수안에 독립적인 스코프 생성되어서 이 함수 안에서 정의된 이름을은
	// 함수 외부에서 접근할 수 없게 됩니다.
	...
})();

 

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

 

math.js

var math = math | {}; // math name space

(function () {
	function sum (a, b) {
		return a + b;
	}

	// 즉시 실행함수 내부는 외부에서 접근할 수 없는 독립적인 공간이기 때문에 
	// 전역 name space에 있는 math에 sum을 할당해줍니다.
	math.sum = sum;
})();

 

app.js

// 현재 sum이라는 함수는 전역스코프가 아닌 전역스코프의 math에 들어있기 때문에 
// math.sum으로 접근해야 합니다.
console.log(math.sum(1, 2));

 

이렇게 ‘sum’이라는 함수를 즉시실행함수로 감싸주면 다른 파일에서 접근할 수 없게 됩니다. 심지어 같은 파일이라할지라도 함수 내부에는 접근할 수 없습니다.

 

이제 ‘sum’이라는 이름은 즉시실행함수 안에 감추어졌기 때문에 외부에서는 ‘sum’이라는 이름을 사용해도 괜찮습니다. 전역에 등록한 ‘math’라는 이름 공간만 잘 활용하면 됩니다.

 

3️⃣ 다양한 모듈 스펙

이러한 방식으로 Javascript 모듈을 구현하는 대표적인 명세가 AMD와 CommonJS입니다.

CommonJS란?

  • CommonJS는 Javascript를 사용하는 모든 환경에서 모듈을 사용하는 것이 목표입니다.
  • exports 키워드로 모듈을 만들고 require() 함수로 불러 들이는 방식입니다.
  • 대표적으로 서버 사이드 플랫폼인 Node.js에서 이 방식을 사용합니다.
  • math.js
exports function sum (a, b) { return a + b; }
  • app.js
const sum = require('./math.js');
sum(1, 2);

 

AMD란?

  • AMD(Asynchronous Module Defintion)는 비동기로 로딩되는 환경에서 모듈을 사용하는 것이 목표입니다.
  • 주로 브라우저처럼 외부에서 Javascript 코드를 로딩해야하는 그런 비동기 환경에서 사용됩니다.

 

UMD란?

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

 

이렇게 각 커뮤니티에서 각자의 스펙을 제안하다가 ES2015에서 “표준 모듈 시스템”을 내 놓았습니다.

 

4️⃣ 표준 모듈 시스템(ES2015)

지금은 Babel과 Webpack을 이용해 “표준 모듈 시스템”을 사용하는 것이 일반적입니다.

 

math.js

export function (a, b) { return a + b; }

 

app.js

// 1. 모든 export를 math라는 이름으로 가져올 때
import * as math from './math.js';

math.sum(1, 2);

// 2. sum만 가져올 때
import {sum} from './math.js';

sum(1, 2);

 

이렇게 export 구문으로 모듈을 만들고, import 구문으로 가져올 수 있습니다.

 

🙄 브라우저의 모듈 지원

안타깝게도 모든 브라우저에서 모듈 시스템을 지원하지는 않습니다.

 

인터넷 익스플로러를 포함한 몇 몇 브라우저에서는 여전히 모듈을 사용하지 못합니다.

 

가장 많이 사용하는 크롬 브라우저만 잠시 살펴보도록 합시다.(크롬은 버전 61부터 모듈 시스템을 지원합니다.)

  • index.html
<!-- 이렇게 해주면 app.js에서 모듈을 사용하고 있다는 것을 알 수 있습니다. -->
...
<script type="module" src="app.js"></script>
...
  • <script> 태그로 로딩할 때 type=”text/javascript” 대신 type=”module”을 사용합니다. app.js는 모듈을 사용할 수 있습니다.
  • 그러나 우리는 브라우저에 무관하게 모듈을 사용하고 싶은데… 바로 그 때가 Webpack이 등장할 차례입니다.

 

정리

'ECMAScript2015' 이전에는 모듈을 만들기 위해 즉시실행함수와 네임스페이스 패턴을 사용했습니다. 이후 각 커뮤니티에서 모듈 시스템 스펙이 나왔고 webpack은 'ECMAScript2015' 모듈시스템을 쉽게 사용하도록 돕는 역할을 합니다.

 

Entry Point를 시작으로 연결되어 있는 모든 모듈을 하나로 합쳐서 결과물을 만드는 것이 webpack의 역할입니다. Javascript 모듈 뿐만 아니라 스타일시트, 이미지 파일까지도 모듈로 제공해주기 때문에 일관적으로 개발할 수 있습니다.

 

webpack의 'loader'와 'plugin'의 원리에 대해 살펴보고 자주 사용하는 것들의 기본적인 사용법을 익혀봅시다.

'Webpack' 카테고리의 다른 글

Webpack - 플러그인(Plugin)  (0) 2024.03.10
Webpack - 로더(Loader)  (0) 2024.03.10
Webpack - 엔트리(Entry)/아웃풋(Output)  (0) 2024.03.10