webpack의 기초에 대해서 알아보기
webpack은 대표적인 자바스크립트 번들러이다.
이 번들러는 js 파일들을 최적화하고 하나의 파일로 만들어주는 역할을 하는데, 거기에 더해서 자바스크립트에서 번들링이 필요한 이유를 이해할 필요가 있다.
webpack의 필요성
기본적으로 js파일은 script 태그를 통해서 html에 연결된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
일반적인 html 파일
이 경우, js 파일이 하나라면 문제가 없지만 대부분의 경우 프로젝트가 조금만 커져도 js 파일은 여러개가 될 것이다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./index.js"></script>
<script src="./hi.js"></script>
<script src="./bye.js"></script>
</body>
</html>
위의 예에서 html에 사용된 js 파일은 각각 다음과 같다.
// index.js
let zombie = "one";
// hi.js
zombie = 777;
// bye.js
window.alert(zombie);
html 파일을 열어보면, 777 이라는 값을 보여주는 알림창이 뜰 것이다.
이번엔 js 파일은 그대로 두고 html 파일을 다음과 같이 수정해보자.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./index.js"></script>
<script src="./bye.js"></script>
<script src="./hi.js"></script>
</body>
</html>
스크립트 태그의 순서가 바뀐것을 확인할 수 있다.
그러자, 이번엔 one이라는 알림을 띄우는 알림창이 나온다.
이렇듯, 자바스크립트는 파일마다 scope가 나뉘지 않는다.
따라서, 수 많은 js 파일을 사용할 때 변수를 공유한다면 스크립트 태그의 서순을 지켜야 하고, 의도치 않게 변수 이름이 중복되면 안된다.
웹팩은 내부적으로 즉시실행함수(IIFE)를 통해서 각 파일마다 scope가 겹치지 않게 해준다.
거기에 더해서 파일의 크기를 줄여주고 최적화까지 해준다.
☕️ 그리고 또 장점이 있는데, babel이나 jsx와 같은 추가적인 기능이나 문법을 사용할 수 있게 loader를 연결할 수 있다.
☕️ 연결된 loader는 webpack과 함께 실행되어 추가적인 기능을 수행해준다.
☕️ babel의 경우는 최신 문법을 호환성이 좋은 과거 문법(es5 등)으로 transpile 시켜주고, jsx 문법 등 자바스크립트 문법이 아닌 다른 문법을 사용하는 파일 역시 자바스크립트로 변환해준다.
기초적인 webpack 사용법
일단, webpack을 사용하기 위해서는 node가 필요하다. (webpack의 런타임 환경은 브라우저가 아니니 당연하다)
🌽 React나 Vue같은 웹 프레임워크에서 node가 필요한 이유에 대해서 어쩌면 의아할 수도 있는데, 사실 내부에 webpack과 같은 번들러의 실행이 우선 필요하기에 node가 필요한 것이다.
node의 설치가 끝났다면, 자연스레 npm역시 설치가 될테니 이제 간단하게 webpack을 사용해보자.
npm init -y
npm 프로젝트를 만들 폴더 내부에서 명령어를 입력한다.
npm i -D webpack webpack-cli
웹팩은 프로덕션 모드에서 필요하지 않기에 개발 의존성으로 설치한다.
웹팩의 실행을 위해서 cli도 함께 설치해준다.
설치 후 웹팩 실행을 위한 스크립트까지 설정해주면 package.json은 다음과 같은 모양이 될 것이다.
🥝 --watch 옵션을 사용하면, 자동으로 파일 변화를 탐지하여 웹팩이 실행된다.
{
"name": "webpack_test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"webpack": "webpack",
"dev": "webpack --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.84.1",
"webpack-cli": "^5.1.1"
}
}
위와 같이 설치가 끝났다면, 이제 웹팩의 설정이 필요하다.
웹팩의 설정은 루트에 webpack.config.js 파일을 생성하여 이곳에 작성한다.
webpack.config.js의 기본적인 설정은 다음과 같다.
const path = require("path");
module.exports = {
// mode: "production",
mode: "development",
entry: {
build: ["./index.js"],
},
module: {
rules: []
},
plugins: [],
output: {
path: path.join(__dirname, "dist"),
},
};
mode는 개발환경과 제품환경을 구분짓기 위한 변수이다. mode가 production이면, 자동으로 코드 최적화가 진행된다.
entry는 웹팩을 통해서 번들링을 할 파일의 목록을 작성하는 곳이다.
만약 entry에 포함되지 않았지만, entry에 포함되는 파일인 index.js에서 import하는 파일이 있다면, 자연스레 그 파일 역시 웹팩 번들링에 포함이 된다.
module은 entry에 포함된 자바스크립트 파일이 어떤 과정을 거칠지 작성할 수 있다. 번들링 과정에서 어떤 파일에 어떤 작업이 일어날지를 명시할 수 있는 곳이다.
예를 들어, babel-loader가 이곳에서 설정된다.
🍊 loader를 설정하여 자바스크립트가 아닌 파일을 하나의 자바스크립트로 변환할 수 있다. (ex. vue-loader, css-loader)
plugin은 웹팩에 추가적으로 기능을 확장하기 위한 공간으로, 보통 웹팩 플러그인 라이브러리를 설치하여 이곳에 추가해주는 식으로 설정한다.
output은 이제 번들링 과정이 끝난 파일에 대한 설정이다. path 옵션을 설정하여 번들링이 끝난 파일이 어디에 저장될지 설정할 수 있다. 이는 절대 경로로 작성되야 하기에 노드 모듈 path와 함께 사용한다.
🍓 이제 index.js를 작성하고 npm run webpack을 실행하면 dist 폴더가 생기고 그 내부에 번들링된 build.js 파일이 생기는 것을 확인할 수 있다.
✨ webpack-dev-server
webpack-dev-server를 사용하면, 웹팩을 개발 서버에서 사용할 수 있다.
npm i -D webpack-dev-server
개발 서버에서 실행된 파일은 코드 변경시 자동으로 리로딩된다.
- package.json
{
...
"scripts": {
"dev": "webpack-dev-server --hot"
},
...
}
webpack.config.js에 추가적으로 설정도 해준다.
devServer: {
devMiddleware: { publicPath: "/build" },
static: { directory: path.resolve(__dirname) },
hot: true,
},
webpack에 babel 연결하기
babel은 브라우저의 호환성을 위해서 자바스크립트 파일을 변환해주는 고마운 라이브러리이다.
babel 설정을 통해서 자바스크립트 파일은 더 넓은 호환성을 지니는 과거의 문법으로 변환될 수 있다.
그렇다면 webpack을 사용하는 환경에서babel을 사용하면 자바스크립트 변환 과정이 두 번 필요한 것일까?
그럴 수도 있겠지만 webpack의 내부에 babel-lodaer를 연결함으로써, 이 과정이 웹팩에서 한 번에 이루어질 수 있다.
일단 babel-loader를 설치해준다. 그리고 좀 더 babel의 성능을 확실하게 알아보기 위해서 jsx 파일을 변환해보자.
npm i babel-loader @babel/preset-react -D
그리고 webpack.config.js를 수정해준다.
const path = require("path");
module.exports = {
mode: "development",
entry: {
build: ["./index.jsx"],
},
module: {
rules: [
{
test: /\.jsx$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [["@babel/preset-react"]],
},
},
],
},
plugins: [],
output: {
path: path.join(__dirname, "dist"),
},
};
index.jsx 파일을 가져와 module에 설정된 rules에 따라서 babel을 적용한다.
node_modules에 포함된 파일은 babel을 적용하지 않는다. (exclude)
🍌 설치한 presets(간단하게 설정 모음집)은 react에 대한 babel 설정이 여럿 들어있고, 이중에 jsx에 대한 지원이 포함된다.
그리고 간단하게 index.jsx 파일을 작성한다.
function App() {
return (
<div>
<p>Hi!</p>
</div>
);
}
작성한 뒤, 다시 npm run webpack을 실행하면, jsx 파일이 build.js 파일로 변환된 것을 확인할 수 있다.
이렇게 간단하게 babel 적용까지 해보았다.
추가적으로, 웹팩을 사용하면 트리 쉐이킹을 적용할 수 있는데, 이를 통해서 라이브러리의 사용되지 않은 메서드들을 포함하지 않는 등의 번들 사이즈 최적화가 가능해진다.
webpack
웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.
webpack.kr
https://www.npmjs.com/package/babel-loader
babel-loader
babel module loader for webpack. Latest version: 9.1.2, last published: 5 months ago. Start using babel-loader in your project by running `npm i babel-loader`. There are 18413 other projects in the npm registry using babel-loader.
www.npmjs.com