웹팩은 모듈 번들러로, 웹 어플리케이션을 구성하는 HTML, JavaScript, CSS, 이미지 등의 모든 파일을 모듈로 보고, 이를 조합해 정적인 에셋으로 변환해주는 역할을 합니다.
✏️ 모듈(Module)
프로그램을 구성하는 코드의 논리적인 단위, 재사용이 가능한 코드 조각을 말합니다. 변수와 함수가 선언될 때 전역 스코프에서 선언되어 충돌하던 문제를 해결합니다. 모듈을 사용하면 모듈 내부에 선언된 변수와 함수는 외부에서 접근할 수 없게됩니다. 모듈은 재사용성이 높고 유지보수가 쉽고, 파일 단위로 관리하면서 코드의 복잡성을 낮출 수 있습니다.
✏️ 정적인 에셋(Static Asset)
런타임에서 동적으로 생성되지 않고 빌드 시점에서 이미 존재하는 파일들을 의미합니다. HTML, CSS, JavaScript 등이 해당합니다. 모듈 번들러로 관리하고, 빌드 시점에 최적화해 애플리케이션을 더 빠르게 효과적이게 합니다.
웹팩은 의존성 트리를 기반으로 해서 애플리케이션을 번들링하므로, 필요한 모듈들만 로드되도록 최적화해 불필요한 네트워크 요청을 줄이고 성능을 향상시킬 수 있습니다.
✏️ 의존성 그래프(Dependency Graph)
모듈 간의 의존성을 파악하고 구성 요소 간의 관계를 시각화한 그래프입니다. 각 파일은 노드로 표시되고, 파일 간의 의존성은 엣지로 표시됩니다. 빌드 도구는 이 그래프를 기반으로 의존성을 파악하고, 변경된 파일을 빌드하여 작업을 최소화합니다.
✏️ 의존성 트리(Dependency Tree)
의존성 그래프의 하위 집합으로 모듈 간의 의존성을 계층적으로 나타내는 구조입니다. 루트노드부터 하위노드까지 모듈 간의 의존성을 나타내고, 특정 노드의 변경사항이 하위 모듈 전체에 영향을 미칩니다.
웹팩은 여러 개의 파일로 나뉘어져 있는 자바스크립트 애플리케이션을 하나의 파일로 묶어주는 역할을 합니다. 이렇게 묶어주는 행위를 번들링이라 하고, 번들링된 파일은 브라우저에서 실행됩니다.
웹앱은 구성하는 모든 자원(HTML, CSS, JavaScript, image 등)을 모듈로 보고, 모두 번들링하여 처리할 수 있습니다. 따라서 다양한 유형의 모듈에 대해 로드와 번들링을 지원하고, 각 모듈 간 의존성을 파악해 최종적으로 하나의 파일로 묶어줍니다.
외에 웹팩의 기능 중에서 가장 중요한 것은, 코드의 최적화와 애플리케이션 개발 과정을 자동화하기 위한 다양한 도구를 제공합니다. 웹팩을 사용하면 자바스크립트 코드를 효율적으로 관리하고 유지보수할 수 있으며, 애플리케이션의 성능을 최적화할 수 있습니다.
웹팩이 애플리케이션의 의존성 그래프를 만들기 위해 진입점(entry point)으로 사용되는 자바스크립트 파일을 말합니다. 엔트리 파일을 시작으로 의존성 그래프를 생성하고, 이를 통해 모듈 단위로 분할하여 번들링합니다.
보통 index.js 파일이 보통 엔트리 파일로 사용됩니다. index.js 파일에서 다른 자바스크립트 파일을 import, require 하는 코드가 있다면 이를 참조해 의존성 그래프를 그리고, 자바스크립트 코드를 하나의 번들 파일로 생성합니다.
웹팩 설정 파일(webpack.config.js)에서 entry 속성을 사용하여 엔트리 파일의 경로를 지정할 수 있고, 여러 개를 지정할 수도 있습니다.
//두 개의 엔트리 파을을 사용해 두 개의 번들파일을 생성하는 예시입니다.
module.exports = {
entry: {
main: './src/main.js',
//vendor: './src/vendor.js'
},
//...
};
웹팩이 번들링한 결과물을 저장할 경로와 파일명을 지정하는 옵션입니다. 즉, 웹팩이 모듈들을 번들링하여 생성한 번들 파일의 위치와 이름을 설정합니다.
웹팩 설정 파일(webpack.config.js)에서 output 속성을 사용해 지정해 번들 파일을 원하는 위치에 저장하고, 웹앱의 빌드 결과물을 관리할 수 있습니다.
[name]
이나 [chunkhash]
와 같은 토큰을 사용해 파일 이름을 동적으로 설정할 수 있습니다.//아웃풋 설정 예시
const path = require('path');
module.exports = {
//...
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
}
};
로더은 자바스크립트 파일과 JSON파일 외의 다른 파일을 모듈로 처리할 수 있도록 해줍니다. 로더를 사용해 웹팩이 파일을 모듈로 간주해 의존성 그래프를 그리게 하고, 코드에서 파일을 불러올 수 있도록 번들링합니다.
✏️ 로더의 작동 방식
로더가 파일을 읽어들입니다.
➡️ 파일을 변환해 모듈 형태로 내보냅니다.
➡️ 웹팩이 변환된 모듈을 의존성 그래프에 포함시킵니다.
➡️ 로더에서 내보낸 모듈을 사용하는 코드에서 require 나 import문으로 불러올 수 있습니다.
로더는 웹팩 설정 파일(webpack.config.js)에서 rules 속성을 사용해 설정할 수 있습니다.
module.exports = {
//...
//🌟🌟🌟 로더가 아니라 'module.rules' 로 적어야 합니다.
module: {
rules: [
{
//css 파일을 모듈로 처리하는 로더입니다. css파일을 불러오기 위해 정규표현식을 사용해 css확장자를 입력합니다.
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
//이미지 파일들을 모듈로 처리하는 로더입니다.
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'images/'
}
}
]
}
]
}
};
예시에서는 파일을 먼저 파일로더로 처리하고, 그 결과물을 다시 css로더를 사용해 순차적으로 적용해 처리합니다. (로더코드는 아래에서 위로 읽혀집니다.)
웹팩의 빌드 프로세스를 자유롭게 커스터마이징할 수 있도록 해주는 도구입니다. 로더가 파일단위로 처리해 번들링된 결과물을 가지고 플러그인은 작업을 수행합니다.
웹팩에서 기본적으로 제공하는 플러그인 외에도, 개발자기 직접 만들어 사용할 수도 있습니다.
🛎️ 대표적인 플러그인
1. HtmlWebpackPlugin : HTML 파일을 생성하고 번들링된 자바스크립트 파일을 자동으로 삽입해 줍니다.
2. MiniCssExtractPlugin : CSS 파일을 분리해 따로 추출할 수 있도록 해주는 플러그인입니다.
3. CleanWebpackPlugin : 빌드 이전에 이전 빌드 결과물을 삭제해주는 플러그인입니다.
4. DefinePlugin : 전역 변수를 설정할 수 있는 플러그인으로, 개발모드와 프로덕션 모드에서 사용하는 변수를 다르게 설정하는 등의 용도로 사용됩니다.
5. HotModuleReplacementPlugin : 브라우저에서 코드 변경 사항이 있을 때 자동으로 새로고침 없이 변경된 내용을 적용해주는 플러그인입니다.
6. BundleAnalyzerPlugin : 번들 파일의 용량과 의존성을 시각화해 분석해주는 플러그인입니다.
웹팩 설정 파일(webpack.config.js)에서 plugins 속성을 사용해 설정할 수 있습니다. 배열로 객체를 추가하면 됩니다.
// HtmlWebpackPlugin을 사용하는 설정 파일
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
plugins: [
//생성자 함수로 플러그인을 생성하여,
new HtmlWebpackPlugin({
//생성할 HTML 파일의 정보를 객체로 전달합니다.
title: 'My App',
template: './src/index.html'
})
]
};
✋🏻 웹팩을 설정하려면 먼저 Node.js와 npm(Node Package Manager)이 설치되어 있어야 합니다. 먼저 설치해 주세요.
node -v npm -v
터미널 또는 명령 프롬프트에 위의 명령어를 입력해 설치되어 있는지 확인할 수 있습니다. 버전정보가 출력되면 설치되어 있는 것 입니다.
mkdir [폴더명]
cd [폴더명]
--save-dev
옵션을 붙입니다.)npm i webpack webpack-cli
touch webpack.config.js
npx webpack
웹팩 설정 파일은 자바스크립트 파일로 작성됩니다. 이 파일은 웹팩의 동작 방식을 정의합니다. 위에서 설명한 주요개념들의 예시를 모아 웹팩 설정 파일을 작성하면 됩니다.
const path = require('path');
//module.exports 객체를 사용해 웹팩 설정을 정의합니다. 이 객체는 웹팩이 사용하는 다양한 속성들을 포함합니다.
module.exports = {
//entry 속성을 이용해 엔트리 파일 경로를 지정합니다. 모듈 번들링을 시작하는 지점입니다.
entry: './src/index.js',
//output 속성으로 번들링한 결과물의 출력경로와 파일이름을 지정합니다.
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
//module 속성으로 로더를 사용해 모듈을 변환하는 방법을 지정합니다.
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
]
},
//plugins 속성으로 웹팩에서 사용하는 플러그인을 설정합니다.
plugins: [
new HtmlWebpackPlugin({
title: 'My App',
template: './src/index.html'
})
]
};
웹팩은 CLI환경을 제공하므로 명령어를 사용해 실행할 수 있습니다.
webpack
: 'webpack.config.js'파일을 참조해 빌드를 실행합니다.webpack --config {config-file-path}
: 'config-file-path' 경로에 위치한 설정파일을 참조해 빌드를 실행합니다.webpack --watch
: 파일 변경을 감지해 자동으로 빌드를 실행하고 결과물을 업데이트 합니다.webpack --mode {mode}
: 빌드 모드를 설정합니다. {mode}에는 development
(개발자모드)와 production
(코드압축과 최적화가 적용되는 배포용모드) 값을 넣을 수 있습니다.webpack-dev-server
: 웹팩 개발 서버를 실행합니다. 소스 코드 변경 시 자동으로 빌드하고 브라우저를 새로고침합니다. 개발서버에서는 결과물을 메모리에 저장하므로 I/O작업 없이 빠른 속도로 개발이 가능합니다.✋🏻 아래 세 가지를 확인 후에 진행합니다.
- 웹팩을 설치했는가(npm install webpack webpack-cli)
- 웹팩 설정 파일(webpack.config.js)을 생성했는가
- 엔트리 포인트가 './src/index.js'일 경우 해당 경로에 파일이 존재하는가
npx webpack
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack Example</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>
npm i style-loader css-loader
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
//test 속성에는 로더를 적용할 파일 확장자나 패턴을 정규식으로 지정합니다.
test: /\.css$/i,
//use 속성에는 적용할 로더를 배열로 지정합니다.
use: ['style-loader', 'css-loader'],
},
],
},
};
import './style.css';
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack Example</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>
npm i style-loader css-loader
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
<script>
태크를 생성해 스타일을 적용합니다.npm i file-loader
//또는
npm i url-loader
import image from './image.png';
const img = document.createElement('img');
img.src = image;
document.body.appendChild(img);
또는
.bg-image {
background-image: url('./image.png');
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack Example</title>
<style>
/* 스타일 로드 확인용 스타일 */
body {
background-color: #f0f0f0;
}
/* 이미지 로드 확인용 스타일 */
.bg-image {
width
프로젝트 개발 시 소스 코드를 컴파일, 번들링, 최적화 등의 작업을 자동화하여 개발 생산성을 향상시킬 수 있습니다. 웹팩의 다양한 기능을 활용해 코드의 용량을 줄이고, 로딩속도를 개선할 수 있습니다.
웹팩 데브 서버는 개발을 위한 간단한 웹 서버입니다. 이 서버를 이용하면 정적파일을 제공하고 코드를 수정할 때마다 변경 사항을 감지해 브라우저를 자동으로 새로고침하고 업데이트합니다.
기본적으로 메모리에 번들된 결과물을 제공합니다. 실제 프로덕션 환경에서 사용되는 결과와 다르며 개발 환경에서만 사용되므로, 실제 서버에 배포할 때는 정적 파일을 빌드해 배포해야 합니다.
npx webpack-dev-server
패키지를 설치하고 명령어를 입력하면 'webpack.config.js'파일을 읽고 개발 서버를 실행합니다. 이후 'localhost:8080'주소로 접속하면 확인할 수 있습니다.
웹팩 데브 서버에는 여러가지 옵션이 있습니다. 예컨대 '--hot' 옵션을 사용하면 소스 코드를 수정할 때마다 변경된 부분만 새로고침해 빠르게 반영할 수 있습니다. '--open' 옵션을 사용하면 서버를 시작할 때 자동으로 브라우저를 열어줍니다.
웹팩은 자동화 도구와 연동해 더 효과적으로 사용할 수 있는데, 이를 통해 자동화된 빌드 및 배포 프로세스를 구축할 수 있습니다.
가장 대표적인 자동화 도구로는 Gulp와 Grunt가 있습니다. 플러그인을 활용해 웹팩을 실행하고 빌드 및 배포과정을 자동화할 수 있습니다.
Gulp는 Node.js 기반으로 작동하며, 자바스크립트를 사용해 작성되는 빌드 도구입니다. 플러그인 기반의 아키텍쳐를 가지고 코드 작성 시 효율적인 스트리밍 방식으로 처리되어 빌드시간을 줄일 수 있습니다.
✏️ 플러그인 기반의 아키텍쳐 : 'gulp-sass'플러그인을 사용하면 scss 파일을 css 파일로 변환할 수 있습니다.
✏️ 스트리밍 방식 : 입력 파일을 메모리에 로드하지 않고 파일을 스트림으로 처리해 빌드시간을 줄일 수 있습니다.
✏️ 자동화 : 파일변경감지 기능을 제공해, 파일이 변경될 때마다 빌드를 자동으로 실행하는 것을 말합니다.
👉🏻 Gulp 설치 사용법
1. 전역에npm i -g gulp
명령어를 입력해 설치합니다.
2. 프로젝트 폴더에서npm i --save-dev gulp
명령어로 설치합니다.
3. 'Gulpfile.js' 파일을 생성하고 코드를 작성합니다.const gulp = require('gulp'); //gulp 작업을 정의하는 역할을 합니다. //'default'라는 Gulp task를 정의하고 실행하면 'Hello, Gulp!'메시지가 출력됩니다. gulp.task('default', function() { console.log('Hello, Gulp!'); });
- 터미널에서
gulp
를 입력해 실행합니다.
대규모 웹 애플리케이션의 번들 크기를 줄이기 위한 기술로, 웹팩과 같은 모듈 번들러를 사용해 구현할 수 있습니다. 코드 스플리팅을 적용하면, 애플리케이션 코드를 여러 개의 작은 청크로 나누어 번들링 할 수 있습니다. 분리된 청크들은 각 독립적으로 로딩되므로, 필요한 코드만 로딩되어 초기 로딩 시간을 줄일 수 있습니다. 웹팩은 자동으로 코드 스플리팅을 처리하고 있습니다.
가장 간단하게 코드 스플리팅을 적용하는 방법은 'import()'함수를 사용하는 것입니다. 해당 모듈이 필요한 시점에 동적으로 로딩되면서 초기 로딩시간을 불일 수 있습니다. 외에도 다양한 설정 옵션을 제공하고 있습니다. 'optimization.splitChunks' 옵션을 사용해 청크의 생성방식을 제어할 수 있고, 'require.ensure' 함수를 사용해 로딩 전략을 제어할 수도 있습니다.
웹팩에서 사용하는 최적화 기법 중 하나로, 프로젝트에 사용되지 않는 코드를 제거해 번들 크기를 줄이는 과정입니다. 자바스크립트 모듈 시스템에서 사용되며, ES6 모듈 시스템에서만 지원되므로 주의해야 합니다.
자바스크립트 코드에서 사용되는 함수나 변수가 실제로 사용되지 않는 경우, 해당 함수나 변수를 번들링 과정에서 제거하기 위해 웹팩은 Abstract Syntax Tree(AST)를 사용해 모듈 간 의존관계를 분석해 사용되지 않는 코드를 식별합니다.
웹팩 설정 파일에서 optimization 속성의 usedExports 옵션을 true로 설정하면 사용할 수 있습니다.
하지만 모든 상황에서 동작하지는 않으며, 함수나 변수가 동적으로 생성되는 경우나 외부 모듈에서 불러오는 경우 제한될 수 있습니다.
웹팩으로 번들링 된 라이브러리를 외부에서 로드할 수 있도록 해서 번들 크기를 줄이고, 공통으로 사용하는 라이브러리를 브라우저 캐시로부터 캐시할 수 있어 로딩 속도를 높일 수 있습니다.
라이브러리 외부화를 설정하려면 웹팩 설정 파일에서 output 속성의 libraryTarget(라이브러리가 어떤 형태로 제공될 지를 지정) 과 library(외부에서 로드할 때 사용할 라이브러리의 이름) 속성을 설정해야 합니다.
module.exports = {
output: {
libraryTarget: 'umd',
library: 'myLibrary'
}
};
예시코드에 의하면 UMD(Universal Module Definition) 형태로 라이브러리를 제공하고, 외부에서 로드할 때 myLibrary 이름으로 사용되도록 설정한 것입니다.
라이브러리 외부화를 설정하면 웹팩은 번들링하지 않고 외부에서 로드할 수 있도록 설정됩니다. 이를 위해 HTML 파일에서 script 태그로 라이브러리를 로드하고, 사용하는 코드에서는 전역객체나 모듈 시스템을 통해 사용하면 됩니다.
하지만 라이브러리 의존성 문제를 주의해야하고, 애플리케이션과의 호환성을 유지해야 합니다.
웹팩은 캐시를 사용해 빌드 시간을 단축하는 캐시 최적화 기능을 제공하고 있습니다. 웹팩에서 캐시는 메모리에 저장되고, 기본적으로 모든 모듈에 대해 계산하여 캐시합니다. 만약 코드의 변화가 없다면(이전과 현재 생성된 캐시의 해시값이 일치) 웹팩은 다시 빌드하지 않아 빌드시간을 줄일 수 있습니다.
캐시최적화를 사용하는 방법은 두 가지가 있습니다.
1. cache 옵션 활성화
module.exports = {
// ...
cache: true,
// ...
};
true로 설정하면 웹팩이 이전 빌드에서 생성한 캐시를 사용해 빌드를 수행합니다.
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: [
'cache-loader',
'babel-loader'
],
exclude: /node_modules/
},
// ...
]
},
// ...
};
리액트는 웹팩을 사용하는 대표적인 라이브러리 중 하나입니다. create react app
을 사용해 리액트 앱을 구성하면, 웹팩을 내부적으로 사용해 JSX 파일을 자바스크립트 파일로 변환하고, CSS 파일을 번들링 해 스타일을 적용하며, 이미지와 같은 정적 파일도 처리할 수 있습니다. 또한, 코드 스플리팅과 같은 기능을 사용해 앱성능을 최적화 합니다.
웹팩과 바벨을 사용해 기본적인 리액트 앱을 빌드하는 'webpack.config.js'파일을 작성하면 다음과 같습니다.
const path = require('path');
module.exports = {
mode: 'development', // 개발 모드
entry: './src/index.js', // 앱의 진입점
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js' // 번들 파일 이름
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader' // 바벨 로더 사용
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] // CSS 로더 사용
},
{
test: /\.(png|jpe?g|gif)$/i,
use: {
loader: 'file-loader', // 파일 로더 사용
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
}
}
]
},
resolve: {
extensions: ['.js', '.jsx'] // 파일 확장자
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: 3000 // 개발 서버 포트
}
};
웹팩은 현재 프론트엔드 개발에서 매우 인기 있는 도구 중 하나입니다.
하지만, 웹팩은 다음과 같은 한게를 가집니다.
1. 강력한 기능을 가진 만큼 복잡해서 학습하기 어렵습니다.
2. 프로젝트 규모와 복잡성에 따라 빌드시간이 길어질 수 있습니다.
3. 설정이 유연한 만큼 초기 설정이 어렵고 복잡합니다.
4. 코드 분할을 구현하기 위해 많은 구성이 필요합니다.
5. 번들링 된 파일의 용량이 커져 로드 속도가 느릴 수 있습니다.
이에 대한 대안으로 Parcel, Rollup, Snowpack 등이 있지만, 그럼에도 불구하고 웹팩은 강력한 로더와 플러그인 생태계가 존재합니다. 개발자는 이를 통해 원하는 대부분의 빌드 작업을 수행할 수 있고, 많은 개발자들이 사용하므로 구글링으로 쉽게 해결 할 수 있는 문제도 많아 개발 생산성이 높습니다. 또 인기 있는 프레임워크의 생태게와 연동성이 높아 웹팩은 여전히 프론트엔드 개발자들에게 대표적으로 사용되는 모듈 번들러입니다.