웹팩(Webpack)은 대표적인 자바스크립트 번들링 툴이다.
React 같은 프레임워크에서는 웹팩이 기본적으로 세팅되어 있지만, 바닐라 자바스크립트로 개발할 때도 번들링 툴을 설치하여 번들 파일을 만드는 것이 권장된다.
왜 번들링 툴이 권장되는가?
지난 포스팅에서 라이브러리를 쉽게 사용하기 위해 npm을 사용하고, npm 사용 시 나오는 node_modules가 너무 무겁기에, 실제 필요한 코드들만 하나의 js 파일로 만들어주는 역할을 번들링 툴이 한다고 언급했었다.
모든 라이브러리를 CDN 링크로 받아오는 게 아닌 이상 번들링 툴은 필수적으로 사용된다.
전통적인 방법은 CDN으로 이루어졌는데, 여기에는 문제가 있다.
js 파일에서 라이브러리를 사용하려면 무조건 html에서 링크를 받아와야 하기 때문에, 결국 js 파일은 html에 종속될 수밖에 없다는 것이다.
그래서 ES6(= ECMAScript 2015) 부터는 import와 export 키워드를 지원하여, 자바스크립트에서 다른 라이브러리의 자바스크립트 모듈을 불러올 수도 있고, 내가 만든 자바스크립트 모듈을 다른 곳에서 import할 수도 있다.
번들링 툴을 사용하지 않는다면 아래와 같이 명시적으로 모듈 선언을 해 주어야 한다.
<script type="module" src="index.js></script>
그러나 각 js 파일을 개별적으로 불러와야 해서 성능상의 문제가 있다.
또한 ES5 이하만 지원하는 구형 브라우저에서는 import / export를 사용할 수 없는데, 웹팩은 Babel과 같은 트랜스파일러를 사용하기 때문에 ES5 코드로 변환해 주는 기능까지 가지고 있다.
이러한 문제 때문에 일반적으로 번들링 툴을 이용한다.
그리고 이번 포스팅을 위한 웹팩 테스트용 코드에서 나는 vs코드의 live-server 플러그인으로 서버를 돌렸는데, 웹팩에서 제공하는 webpack-dev-server를 설치해도 된다.
전통적인 방식의 바닐라 자바스크립트
index.html의 구조는 아래와 같다.
<!DOCTYPE html>
<head>
<title>
webpack test
</title>
<script src="https://cdn.jsdelivr.net/npm/figlet@1.7.0/lib/figlet.min.js"></script>
<script src="./index.js"></script>
</head>
<body>
<button onclick="printAsciiArt()">
아스키 아트 출력
</button>
<div style="font-family:Arial" id="ascii"></div>
</body>
html에서 index.js를 참조해주고 있고, CDN 링크로 라이브러리를 사용한다.
figlet은 예시로 사용한 라이브러리로, 문자열을 요청하면 아스키 아트를 응답해준다.
const printAsciiArt = () => {
figlet("Hello World", (_, data) => {
document.getElementById("ascii").innerText = data;
});
}

가독성이 그지같긴 하지만 일단 출력이 된다.
웃긴게 require("figlet")을 써서 node.js 환경에서 출력하면 이쁘게 잘 나옴.
웹팩 설치 / 환경설정 / 번들링 해보기
아래는 웹팩, 그리고 웹팩의 키워드를 CLI 환경에서 사용할 수 있도록 하는 패키지 설치 과정이다.
npm i --save webpack
npm i --save webpack-cli
그리고 프로젝트 루트 폴더에다가 webpack.config.js 파일을 만든다. 웹팩을 설정하기 위한 파일이다.
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js"
}
};
그리고 위 코드를 복붙한다. 참고로 아무런 웹팩 설정을 하지 않았어도 위 코드는 웹팩의 기본 세팅과 동일하게 동작한다.
즉, 웹팩은 기본적으로 ./src/index.js 파일을 입력(entry)으로 하여 /dist/main.js 파일로 번들링하는 것이다.
위 구조를 토대로 entry와 output을 원하는 경로로 변경해보자.
entry는 여러 개 있어도 상관없다. MPA에서 웹팩을 사용할 때는 어쩔 수 없이 여러개가 들어가야 할 것이다.
유의할 점은 entry는 상대 경로여야 하지만 output은 무조건 절대 경로로 입력해야 한다.
그리고 __dirname은 프로젝트 루트 경로를 의미한다.
세팅이 끝났다면 프로젝트 루트 경로에서
npx webpack
를 입력한다.

output 경로로 가 보면 번들링 결과물을 볼 수 있는데, 보다시피 매우 난해한 코드로 이루어져 있다. 보안적으로 조금의 이점은 가지고 있다고 한다.
번들링된 파일 적용해보기
<!DOCTYPE html>
<head>
<title>
webpack test
</title>
<script src="./src/index.js"></script>
</head>
<body>
<button onclick="printAsciiArt()">
아스키 아트 출력
</button>
<div style="font-family:Arial" id="ascii"></div>
</body>
html 코드에서 CDN 링크를 삭제한다.
import figlet from "figlet";
const printAsciiArt = () => {
figlet("Hello World", (_, data) => {
document.getElementById("ascii").innerText = data;
});
}
그리고 import로 라이브러리를 불러오도록 변경한다.

번들링된 파일이 아닌 원본 js 파일에 접근하려 하면 다음과 같은 에러가 발생한다.
웹팩으로 js를 번들링하면 js 파일 하나하나가 웹팩 자체 모듈화되기 때문이다.
<script src="./dist/main.js"></script>
번들링된 파일로 경로를 변경한다.
그리고 버튼을 눌러서 printAsciiArt 함수를 실행하려고 하면

또 에러가 발생한다.
이번 에러는 html에서 직접적으로 모듈에 접근할 수 없기에 발생한 것이다.
이번엔 아래 코드처럼 버튼 이벤트 대신 js에서 바로 함수를 호출하도록 해 보았다.
import figlet from "figlet";
const printAsciiArt = () => {
figlet("Hello World", (_, data) => {
document.getElementById("ascii").innerText = data;
});
}
printAsciiArt();

정상적으로 동작한다. 같은 모듈 안에서는 얼마든지 printAsciiArt 함수에 접근이 가능한 것이다.
웹팩은 기본적으로 global하게 함수를 제공하지 않기에 일어나는 일이다.
물론 명시적으로 전역 함수로 지정하는 방법도 있는데,
window.printAsciiArt = printAsciiArt;
js 파일에 다음과 같은 코드를 추가해 주면 된다. 정상적으로 함수가 호출된다.
이 방법이 싫다면 document.getElementById로 이벤트를 조작하는 방법을 사용해야 한다.
아래 링크를 참고하면 좋다.
Basic webpack not working for button click function - Uncaught Reference error: undefined
I have a basic HTML page with a button: <!DOCTYPE html> <html lang="en"> <head> ... </head> <body> <button id="button" onclick="uclicked()">Click me</b...
stackoverflow.com
웹팩의 Loader 기능 사용해보기
리액트를 사용하면 import "./style.css"; 로 간편하게 css를 로드할 수 있는데, 이 설정도 웹팩에서 할 수 있는 설정이다.
바로 Loader 기능을 이용하면 된다.
npm install --save css-loader style-loader
위와 같이 css 로더와 스티일 로더를 설치해 css 파일을 로드할 수 있다.
css 로더는 스타일 시트를 모듈로 변경하는 로더이고, 그 모듈을 DOM에 추가하기 위해선 style 로더가 필요하다.
그리고 아래와 같이 webpack.config.js에서 관련 설정까지 해 주면 준비는 완료된다.
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js"
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
};
index.js와 같은 경로에 style.css 파일을 만들고 내용을 입력해주자.
#ascii {
color: red;
}
index.js에서 import를 해 주면
import "./style.css";

정상적으로 스타일이 적용되었다.
로더는 이 밖에도 여러 가지가 있다.
자주 쓰는 것들은 다음과 같다.
- babel-loader: 구형 브라우저(ES5 이하)에 호환되도록 변환
- file-loader: html 안에 있는 파일(이미지 등)을 로드
- html-loader: html를 자바스크립트 모듈로 변환
- sass-loader: sass/scss 파일을 css로 변환
- ts-loader: 타입스크립트 파일을 자바스크립트로 변환
웹팩 자동 빌드
현재 js가 변할 때마다 계속해서 npx webpack 명령어로 빌드를 해 줘야 하는데, 개발할 때 매우 번거로운 일이 아닐 수 없다. 일전에 tailwind처럼 웹팩도 자동으로 변경 사항을 감지하여 빌드해주는 기능이 있는데,
npx webpack --watch
다음과 같이 뒤에 --watch라는 옵션을 붙여주기만 하면 된다.
교훈: 그냥 리액트 쓰자(아님)

추석 연휴 잘 보내세요 ^^
'IT > JavaScript & TypeScript' 카테고리의 다른 글
| [JavaScript] 스택, 큐 구현 (0) | 2024.10.01 |
|---|---|
| [JavaScript] 코딩테스트에 유용한 자바스크립트 문법 (1) | 2024.09.25 |
| [TypeScript] 타입스크립트 기초 (0) | 2024.07.03 |
| [JavaScript/TypeScript] 반복문 안에 있는 비동기 처리 방법 (0) | 2024.05.10 |
| [JavaScript] 클로저를 통해 코드 최적화(Optimizing)하기 (0) | 2024.04.29 |