최근 Javascript로 SPA만들기 사이드 프로젝트를 진행하며 웹팩설정 후 배포까지 진행해 보았다. 배포과정속에서 공부한 내용들을 회고하며 웹팩의 주요 개념들을 정리해본다.
Webpack은 여러개 파일을 하나의 파일로 합쳐주는 모듈 번들러
(Module bundler) 이다.
표준화된 모듈화 기법
이 등장한 것은 ES6(ES2015)부터인데, Webpack이 필요한 이유를 알기 위해서는 모듈화 역사를 알아볼 필요가 있다.
💡 모듈은 프로그래밍 관점에서 특정 기능을 갖는 작은 코드 단위를 의미한다.
자바스크립트는 script 태그를 사용하여 외부의 스크립트 파일을 가져올 수는 있지만, 파일마다 독립적인 파일 스코프를 갖지 않고 하나의 전역 객체
(Global Object) 를 공유한다.
<!DOCTYPE html>
<html>
<head> </head>
<body>
<script src="./src/math.js"></script>
<script src="./src/app.js"></script>
</body>
</html>
math.js
와 app.js
는 같은 전역스코프를 공유하기에 내부에 동일한 함수명
이나 변수명
이 있다면 충돌
하게 되는 문제가 발생한다.
즉, 스코프 문제가 발생하고, 의존성 관리 문제도 해결되지 않으므로 모듈화를 구현하기 어렵다.
즉시 실행 함수 표현(IIFE, Immediately Invoked Function Expression) 은 정의되자마자 즉시 실행되는 Javascript Function 를 말한다.
var math = (function () {
var result = 0;
return {
sum : function (a,b) {
result = a+b;
return result;
}
}
})();
console.log(math.sum(3,5)) // 8
console.log(result); // Uncaught ReferenceError: sum is not defined
IIFE
와 클로저 원리를 이용하여 스코프 문제를 해결
했지만 바로 실행한다는 점에서 모듈화의 해결책은 아니다. 이렇게 모듈기능은 반드시 해결해야할 과제였다. 그래서 제안된 것이 CommonJS
와 AMD
이다.
💡 모듈화를 위해서는 3가지 요건
스코프
,정의
,사용
을 충족해야한다.
1. 스코프 - 각각의 모듈은독립적인 스코프
를 가져야하며
2. 정의 - 모듈을 정의할 수 있는가(만들 수 있는가)
3. 사용 - 정의된 모듈을 가져다사용
할 수 있어야 한다.
1) CommonJS
2009년 등장한 CommonJS는 각각의 파일이 독립적인 스코프를 가지며, exports
키워드로 모듈을 만들고 require()
함수로 임포트하는 방식 전역변수와 지역변수를 분리하여 모듈이 독립적인 실행 영역을 갖게 된다.
CommonJS는 모든 파일이 로컬에 존재하여 바로 불러올 수 있으며,동기적
으로 동작하는 특징이 있다.
이 방식은 브라우저
에서는 필요한 모듈을 모두 내려받을 때까지 아무것도 할 수 없는 결정적인 단점이 있다.
2) AMD
동기적인 특징을 가진 CommonJS를 브라우저에서 비동기로 모듈을 사용하고 싶은 그룹이 독립해 나온 것이 AMD(Asynchronous Module Definition)이다.
define(id?, dependencies? , factory);
require([modulePath], function(module)(){
// module을 활용하는 실제 코드
}
AMD API 명세로 구현된 대표적인 도구는 dojo toolkit
과 reuqire.js
가 있다.
2015년, ES6에 자바스크립트에 정식으로 모듈 시스템
이 도입되었다.
모듈 시스템이 도입되면서 import
, 와 export
키워드만으로 모듈화
가 가능하게 되었다.
export default App;
---
import App from './App.js';
하지만 새로운 문제
가 발생하였는데, 모듈을 이용해서 편리하게 프로그래밍을 하는 것은 좋으나, 모든 파일
을 네트워크 통신
을 통해 가져와야 했다.
// index.js
import a from './a.js'
import b from './b.js'
import c from './c.js'
import d from './d.js'
function sum () {
return a+b+c+d;
}
console.log(sum());
css나 이미지 파일 등도 하나하나 네트워크 통신을 통해 가져와야 했다.
이러한 점을 개선하기 위해 등장한 것이 모듈 번들러
이다.
모듈 번들러는 여러 모듈을 모아 번들링 함으로 하나의 파일로 병합 및 압축 해주는도구이다.
- 자바스크립트 변수 유효 범위
웹팩은 변수 유효 범위의 문제점을 ES6의 Modules 문법
과 웹팩의 모듈 번들링
으로 해결한다.
- 브라우저별 HTTP 요청 숫자의 제약
브라우저 | 최대 연결 횟수 |
---|---|
익스플로러 7 | 2 |
익스플로러 8 ~ 9 | 6 |
익스플로러 10, 11 | 8, 13 |
크롬 | 6 |
사파리 | 6 |
오페라 | 6 |
안드로이드, iOS | 6 |
웹팩을 이용해 여러 개의 파일을 하나로 합치면 위와 같은 브라우저별 HTTP 요청 숫자 제약을 피할 수 있다.
- Dynamic Loading & Lazy Loading 미지원
Require.js와 같은 라이브러리를 쓰지 않으면 동적으로 원하는 순간에 모듈을 로딩하는 것이 불가능 했다. 그러나 이젠 웹팩의 Code Splitting
기능을 이용하여 원하는 모듈을 원하는 타이밍
에 로딩할 수 있다.
모듈 번들러의 종류는 webpack
이외에도 여러가지가 있다. 그 뒤로 esbuild
, rollup
, vite
가 많이 사용되고 있다.
이처럼 webpack이후에도 tree-shaking
을 위하여 rollup plugin
을 포함한 vite
가 나오거나 vercel에서 webpack
의 후속작이라는 타이틀은 건 rust기반의 turbopack
이 나오는 등 모듈 번들러 시장은 계속해서 진화하며 빠르게 생태계가 변화하고 있다.
기존에 나와있는 라이브러리와 프레임워크들의 탄생배경을 살펴보면 항상 문제점의 개선을 위한 탄생이라고 생각한다.
빠르게 변화하는 개발 생태계에 적응하기 위하여 나와있는 라이브러리와 프레임워크에 대한 공부도 중요하겠지만, 근본적으로 해당 도구들이 왜 나왔을까? 어떠한 점을 개선했을까 등을 이해하는게 먼저인 것 같다.
참고 영상
10분 테크톡 - 썬의 모듈 번들러와 빌드도구
자바스크립트 모듈의 안타깝고(?) 치열한 역사
참고 자료
웹팩 핸드북
웹팩을 쓰는 이유