React 공식 문서에서도 프레임워크와 함께 사용하는 것을 권장하고 있지만, 실제로는 여전히 Next.js와 같은 프레임워크 없이 React만 사용하는 개발 사례가 많다. 이 경우 Vite를 비롯해 Rollup, Parcel, Webpack, 그리고 CRA(Create React App)와 같은 도구를 사용해 개발하는 경우가 이에 해당한다.
따라서, 프레임워크가 제공하는 번들링 환경에만 의존하기보다는 번들링 도구에 대한 이해가 여전히 중요하다. 특히, 풍부한 자료와 널리 사용되는 Webpack을 중심으로 번들링에 대해 정리하려고 한다.
더불어 Next.js에서도 Turbopack이라는 새로운 번들러가 도입되었지만, 현재 개발 환경에서만 사용되며, 여전히 Webpack을 주요 번들러로 사용하고 있다. 이러한 이유로 Webpack은 번들링 도구를 이해하는 데 있어 중요하다고 생각한다.
번들러
번들러는 여러 개의 자바스크립트 파일과 그 외 관련 리소스(CSS, 이미지 등)를 하나의 파일 또는 여러 개의 최적화된 파일로 묶어주는 도구이다.
번들링이 왜 필요할까?
그냥 개발자가 작성한 그대로의 파일 구조를 사용자에게 보여줘도 문제가 없어 보일 수 있다. 하지만 성능과 유지보수 측면에서 여러 가지 문제가 발생할 수 있다.
번들러를 사용하는 이유는 다음과 같다.
- 의존성 관리
자바스크립트 파일 간의 의존성을 관리하면서 로드 순서와 충돌 등의 문제를 방지한다. 예를 들어, 특정 파일이 다른 파일에 의존하고 있다면, 번들러가 이를 파악하고 올바른 순서로 실행되도록 처리한다. - 네임스페이스 충동
여러 파일에서 동일한 변수명이나 파일명을 사용할 경우, 변수 스코프가 겹치거나 충돌할 위험이 있다. 번들러는 이러한 충돌을 방지하기 위해 각 파일을 모듈화하고, 안전한 범위 내에서 동작하도록 설정한다.
- 네트워크 요청 최적화
브라우저가 홈페이지를 로드할 때 많은 파일을 요청하면 네트워크 성능이 저하될 수 있다. 번들러는 리소스 파일을 하나로 묶거나 필요한 파일의 크기를 최적화하여 네트워크 요청 횟수를 줄임으로써 성능을 개선한다.
Webpack
Webpack은 여러 파일을 하나의 번들로 묶어주는 모듈 번들러이다.
주로 웹 애플리케이션 개발에 사용되며, 다양한 파일 형식을 처리하고 복잡한 의존성을 효율적으로 관리한다.
Webpack의 특징
- 모듈 번들링
다양한 파일(자바스크립트, CSS, 이미지 등)을 하나의 파일로 묶어 브라우저가 한 번에 로드할 수 있도록 처리한다. 이를 통해 네트워크 요청을 최소화하고, 로딩 속도를 개선할 수 있다. - 로더 시스템
Webpack은 자바스크립트 외에도 CSS< 이미지, JSX 등 다양한 파일 형식을 처리할 수 있다.
로더를 통해 이러한 파일들을 변환하여 번들에 포함할 수 있다.
예) style-loader, css-loader, babel-loader 등. - 플러그인
Webpack은 기본적인 번들링 외에도 다양한 작업을 수행하기 위해 플러그인을 제공한다.
- HTML 파일 자동생성 : HtmlWebpackPlugin
- 코드 압축 및 최적화 : TerserPlugin
- 파일 분리 : SplitChunksPlugin
- HMR (Hot Module Replacement)
개발 환경에서 코드 변경 시 전체 페이지를 새로고침하지 않고, 변경된 모듈만 새로고침하는 기능을 제공한다.
Webpack을 사용한 React 개발 환경 구성
Webpack을 활용해 CRA(Create React App) 없이 React 개발 환경을 간단히 구현해보려고 한다.
1. 필요한 패키지 설치
개발에 필요한 패키지
yarn add -D webpack webpack-cli webpack-dev-server babel-loader css-loader style-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin
배포 환경에 필요한 패키지
yarn add react react-dom
2. Webpack 설정 파일 작성
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
resolve: {
extensions: [".js", ".jsx"],
},
module: {
rules: [
{
test: /.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /.js|.jsx$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
}),
],
devServer: {
hot: true,
},
};
mode
mode: "development",
Webpack의 동작 모드를 설정하는 옵션이다. development와 preduction, 2개의 모드를 가지고 있다.
- development
개발 모드로, 디버깅과 빠른 빌드를 위해 최적화가 적용되지 않고 코드가 압축되지 않는다. - production
배포 모드로, 코드가 압축되고 최적화 상태로 빌드된다.
entry
entry: "./src/index.js",
번들링의 진입점을 설정한다.
예를 들어, ./src/index.js를 설정하면 해당 파일과 그 안에서 불러오는 모든 모듈이 번들에 포함된다.
output
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
- filename
번들 파일의 이름을 지정한다. - path
번들 파일의 저장 경로를 지정한다. path.resolve(__dirname,"dist")는 프로젝트 루트의 dist 폴더에 저장하겠다는 의미이다.
resolve
resolve: {
extensions: [".js", ".jsx"],
},
import를 할 때 생략할 수 있는 확장자를 추가할 수 있다.
React에서 컴포넌트 또는 모듈을 import할 때 일반적으로 확장자를 생략하는데, 그 기능을 resolve의 extensions에서 제공하고 있는 것이다.
module
module: {
rules: [
{
test: /.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /.js|.jsx$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
],
},
파일 처리 규칙을 정의한다.
- CSS 파일
style-loader와 css-loader를 사용해서 처리한다.
- css-loader: CSS 파일을 읽어서 JavaScript로 변환한다.
- style-loader: 변환된 CSS를 브라우저에 인라인 스타일로 적용한다.
- 순서가 중요한데, [style-loader, css-loader]는 css-loader가 먼저 실행되고 style-loader가 실행된다.
- JS 파일
babel-loader를 사용해 ES6+ 및 React(JSX) 코드를 트랜스파일한다.- 트랜스파일하는 파일의 확장자를 .js와 .jsx로 설정하여 두가지를 사용할 수 있게 설정하였다.
- exclude : node_modules는 번들링에서 제외된다.
plugins
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
}),
],
로더가 처리하지 못하는 작업을 처리한다.
- HtmlWebpackPlugin : 번들링된 자바스크립트 파일을 HTML 파일에 자동으로 삽입해준다.
devServer
devServer: {
hot: true,
},
HMR 설정으로, 코드 변경 시 전체 페이지 새로고침 없이 변경된 모듈만 새로고침하여 개발 속도를 높인다.
3. HTML 파일 생성
Webpack 설정에서 HtmlWebpackPlugin의 template 옵션에 지정된 HTML 파일을 만들어준다.
이 파일은 애플리케이션의 기본 HTML 템플릿으로 사용된다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
- <div id="root"> : React 애플리케이션이 렌더링될 컨테이너 역할을 한다.
- template : Webpack이 번들링된 스크립트를 이 HTML 파일이 자동으로 삽입한다.
4. JavaScript 파일 생성
React 코드를 작성하기 위한 진입점 파일을 만들어준다. Webpack 설정에서 entry: "./src/index.js"로 지정된 파일이다.
import React from "react";
import ReactDom from "react-dom/client";
const root = ReactDom.createRoot(document.getElementById("root"));
root.render(<div>Hello</div>);
- ReactDom.createRoot : React 18버전부터 사용되는 메서드로, 애플리케이션의 루트 DOM 컨테이너를 생성한다.
- document.getElementById("root") : React 애플리케이션이 렌더링될 컨테이너를 지정한다.
- root.render(<div>hello</div>) : React 컴포넌트를 렌더링한다.
5. package.json 설정
Webpack을 통해 React 개발 환경을 실행하려면 scripts 섹션에 Webpack Dev Server를 실행하는 명령어를 추가해야 한다.
"scripts": {
"start": "webpack serve --open",
"test": "echo \"Error: no test specified\" && exit 1"
},
- webpack serve --open
개발 서버를 시작할 수 있다. --open 옵션을 통해 서버 시작 시 브라우저를 자동으로 열어준다.
'React > 이론' 카테고리의 다른 글
[React] DOM vs Virtual DOM (0) | 2022.11.08 |
---|---|
[React] 렌더링 (0) | 2022.11.07 |
[React] 브라우저의 렌더링 과정 (0) | 2022.11.06 |
[React] Custom Hook (1) | 2022.10.22 |
[React] Redux (1) | 2022.10.14 |