What is Webpack?
Webpack 이란 무엇인가?
웹팩은 모듈 번들러이다.
모듈 번들러란 웹 애플리케이션을 구성하는 자원(HTML, CSS, Javascript, Image 등)을 모두 각각의 모듈로 보고 이를 조합해서 하나의 결과물을 만드는 도구를 의미한다.
왜 Webpack이 필요 한가?
웹팩을 사용해야 하는 이유를 이해하기 위해선 번들러를 사용하기전에 어떻게 자바스크립트를 사용했는지 알아야 한다.
웹팩에서 해결하고자 하는 기존의 문제점은 다음 4가지다.
- 자바스크립트 변수 유효 범위
- 브라우저별 HTTP 요청 숫자의 제약
- 사용하지 않는 코드의 관리
- Dynamic Loading & Lazy Loading 미지원
자바스크립트 변수 유효 범위
브라우저에서 자바스크립트가 동작하는 방법은 두 가지다.
첫째, 각 기능이 있는 스크립트를 추가한다.
<!-- index.html -->
<html>
<head>
<!-- ... -->
</head>
<body>
<!-- ... -->
<script>
var num = 10;
function getNum() => {
console.log(num);
};
</script>
var num = 20;
function getNum() => {
console.log(num);
};
<script>
</script>
<script>
getNum(); // 20
</script>
</body>
</html>
이와 같은 방법은 복잡한 애플리케이션을 개발할 때 모든 변수의 이름을 기억하지 않는 이상 변수가 중복되는 문제가 있다.
둘째, 하나의 거대한 자바스크립트 파일은 만들어 사용한다.
이 방법은 유효범위와 크기, 가독성, 유지보수의 문제를 발생시킬 수 있다.
이러한 문제를 해결하려면 파일 단위로 변수를 관리할 수 있어야 했는데 AMD, Common.js와 같은 모듈화 라이브러리를 통해 문제를 해결했다.
브라우저별 HTTP 요청 제한
TCP 스펙에 따라 브라우저에서 한 번에 서버로 보낼 수 있는 HTTP 요청 숫자는 제약되어 있다.
스크립트가 많을 수록 웹 페이지를 로드하는 시간이 늘어나기 때문에 HTTP 요청 숫자를 줄이는 것이 웹 애플리케이션의 성능을 높여줄 뿐만 아니라 사용자가 사이트를 조작하는 시간을 앞당겨 줄 수 있다.
사용하지 않는 코드의 관리
애플리케이션을 제작하다 보면 사용되지 않는 라이브러리나 코드들이 생기기도 하고 라이브러리를 사용하더라도 일부의 기능만을 사용하기도 하는데 모든 코드를 번들 파일에 포함 시킨다면 용량의 증가로 이어진다. 이를 해결하기 위해 사용하지 않는 코드를 번들 파일에서 제외하는 tree shaking이라는 개념이 rollup 모듈 번들러를 통해 대중화되었다.
Dynamic Loading & Lazy Loading 미지원
현재 사용자가 보고 있는 웹페이지는 전체 코드의 일부이다. 그렇기 때문에 성능 향상을 위해 웹 페이지를 보여줄 때 모든 코드를 로드하는 것이 아닌 필요한 모듈만 동적으로 로딩해야 했는데
Require.js와 같은 라이브러리를 쓰지 않으면 동적으로 원하는 순간에 모듈을 로딩하는 것이 불가능했다.
위와 같은 문제들을 해결하려면 여러 가지의 라이브러리들을 사용해야 하는 불편함이 있다.
그렇다면 이러한 문제를 손쉽게 해결할 방법은 무엇일까?
바로 Webpack이다.
웹팩은 위에서 살펴본 문제들을 추가적인 라이브러리 설치 없이 웹팩 하나로 해결한다.
자, 그럼 실제로 웹팩이 어떻게 작동하는지 알아보자.
Core Concept
- Entry
dependency graph를 만들기위해 탐색을 시작하는 지점이다.
// webpack.config.js
module.exports = {
entry: "./src/index.js"
}
entry
속성에 입력한 파일을 entry point
로 설정한다. dependency graph
를 위해서 entry point
를 사용하여 필요에 따라 모듈을 만든다. (필요하지 않다면 tree shaking을 통해 번들에 포함시키지 않는다.)
위 예시에서 bootstrap.main.ts
는 앱에서 처음으로 로드되고 시작되는 파일, 즉 entry point이다. 웹팩은 entry point에서 시작하여 애플리케이션에서 필요한 모든 모듈을 포함하는 dependency graph
를 재귀적으로 build한다.
- Output
번들을 배포할 절대 경로를 정의한다.
module.exports = {
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
}
}
filename
은 웹팩으로 build 한 결과물인 번들 파일의 이름을 의마하고, path
는 해당 파일의 경로를 의미한다. path
는 절대 경로
를 사용해야 한다. 상대 경로를 지정할 경우 에러가 발생한다.
- Loader
webpack은 javascript와 JSON 파일만 이해할 수 있다.
그래서 application에 필요한 다른 type의 파일을 처리하기 위해서 그에 맞는 Loader가 필요하다.
Loader는 javascript에게 none-javascript
모듈을 어떻게 처리하는지 알려준다.
module.exports = {
module: {
rules: [
{
test: /\\.s[ac]ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader",
]
},
}
}
}
module 객체 안에는 rules 옵션이 있고 rules는 기본적으로 test와 use 두 가지 옵션이 있다.
test는 어떤 파일을 처리할 것인지를 알려주고 use는 어떤 loader를 사용하여 처리할 것인지를 알려준다.
loader는 코드를 아래부터 읽기 때문에 위처럼 sass를 사용하는 경우, sass ⇒ css ⇒ js로 변환될 수 있도록 코드를 작성해야 한다.
sass를 css로 컴파일하고 css를 js로 컴파일하고 style을 dom에 적용한다.
webpakc5에서는 asset/module이 추가되었다.
rules에 type 옵션으로 사용할 수 있다.
module: {
rules: [
{
test: /\\.png$/,
type: "asset/resource"
}
]
},
asset/module로 처리하는 못하는 파일을 loader로 처리한다. resource 파일을 가져와서 수정된 상태를 return 한다.
css나 babel처럼 여러 loader를 사용할 수 있다.
js 말고도 다른 모든 파일들은 이러한 기능적 변환에 의해 일부 표현에서 js 모듈로 변환될 수 있다.
또한 exclue
, include
, enforce
등의 속성을 사용해서 모듈을 필터링할 수 있다.
{
test: /\\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
- Plugins
plugin
은 함수를 적용하고 전체 컴파일 수명 주기에 연결할 수 있는 ES5 클래스다.
쉽게 말해서 plugin
은 웹팩의 기본적인 동작에 추가 기능을 제공한다.loader
와 비교하면 loader
는 파일을 해석하고 변환하는 과정에 관여하는 반면, 플러그인은 해당 결과물의 형태를 바꾸는 역할을 한다.plugin
을 사용하면 번들을 최적화하거나, 애셋을 관리하고, 또 환경 변수 주입 등과 같은 광범위한 작업을 수행할 수 있다.plugins
배열 안에 new 생성자로 실행하는 방식으로 사용된다.
const HelloWorldPlugin = require('hello-world');module.exports = {
// ... configuration settings here ...
plugins: [new HelloWorldPlugin({ options: true })]
};
- Mode
mode는 환경 별로 웹팩을 build 할 수 있도록 해준다.
development, production, none 값을 사용할 수 있다.
module.exports = {
mode: 'production',
};
development, production, none 값을 사용할 수 있다.
Summary
웹팩의 목적
- 자바스크립트 변수 유효 범위
- 브라우저별 HTTP 요청 숫자의 제약
- 사용하지 않는 코드의 관리
- Dynamic Loading & Lazy Loading 미지원
를 한 번에 해결하기 위해
Core Concept
- Entry — 번들링 시작점
- Output — 번들 결과물의 위치
- Loader — none-javascript 모듈의 처리 방법
- Plugin — 기본기능 외의 추가 기능
- Mode — 환경별로 build
Reference