안녕하세요.
Hynn 입니다.
이번 포스팅에서는 React 와 같이 활용하게 될 Webpack 에 대한 기초적 사항만을 알아보도록 하겠습니다.
===========
===========
1. 왜 Webpack 을 사용하는가?
Webpack은 서비스의 명칭은 아니고, Library 의 명칭입니다.
유사한 서비스들도 많지만, Webpack 보다 먼저 나온 서비스도 존재합니다.
이 Webpack 과 같은 라이브러리가 가지고 있는 정식명칭은 "Module-Bundler" 라고 하며, 최초에는 대규모 프로젝트의 복잡성을 관리하기 위해 출발한 라이브러리입니다.
일반적으로 Module-Bundler 는 아래와 같은 형태의 서비스를 제공합니다.
"여러개의 module을 하나의 파일로 병합하는 Bundling 처리"
쉽게 이해한다면 아래와 같은 작업으로 이해하시면 좋을 거 같습니다.
먼저 그림으로 살펴보도록 하겠습니다.

위의 한줄요약을 그림으로 표현하면 이렇게 표현이 가능합니다.
흔히 컴퓨터에서 우리가 여러개의 파일을 압축하여 하나의 압축파일로 저장하고 이를 Cloud 나 외장 저장장치에 저장하는 형태로 사용을 하였을 겁니다.
모듈번들러는 바로 이러한 개념을 개발에도 접목시킨 라이브러리 이지만 몇가지 포인트가 있습니다.
바로, 여러개의 "모듈"을 하나의 "번들"로 처리하는 과정에서 코드에 몇가지 작업이 수행되기 때문입니다.
- Tree Shaking
- Dead Code elimination
- Code splitting
즉, 여러개의 모듈을 하나의 번들러로서 처리하는 과정에는, 위의 3가지 작업이 수행되면서, 코드의 효율성을 증가시키는 역활을 1차적으로 담당하게 됩니다.
이 각 서비스는 사용되는 모듈 번들러별로 다르게 적용될 수 있기 때문에, 밑에서는 각 모듈 번들러 서비스 중 몇가지의 특징도 같이 알아볼 예정입니다.
1) Tree Shaking
이 기능은 JavaScript 모듈 번들러에서 사용하는 기술입니다.
이 기능의 핵심은 최종 번들러의 파일, 즉 결과물로 나오는 번들러에 실제 작성은 되어 있지만 사용하지 않는 코드를 제거하는 기능입니다.
예를 들어 주석처리가 된 코드라거나, 변수나 method, 함수등이 작성이 되어 있지만 실제 코드에서 사용하지 않는 코드가 있는지 분석합니다.
이 분석결과를 토대로 최종결과물에서는 실제 사용하지 않는 코드를 제외하고 생성함으로서, 결과물로 나오는 번들러의 크기와 코드 길이를 줄임으로서 효율성을 향상시키는 기능입니다.
2) Dead Code Elimination
이 기능은 위의 기능과 유사하면서도 다른 기능을 가지고 있습니다.
단어 그대로 죽은 코드를 제거하는 기능이지만, JavaScript 에서 컴파일러 과정에서 코드의 테스트 결과가 항상 오류를 발생시키는 코드일 경우를 식별하고 이를 제거하는 기능입니다.
하지만 이 기능은 때때로, 의도치 않은 코드가 삭제됨으로 인해 문제가 발생될 수 있어, 실제 원문 코드에서도 오류를 사전에 체크하는 것이 중요하다고 할 수 있습니다.
3) Code Splitting
이 기능은 하나의 큰 JavaScript 파일을 작은 파일로 분할해서 코드를 조각화 하는 것이 가장 큰 특징입니다.
즉 이 기능을 적용함으로서, 예를 들어 Index.html 에 접속하면 index.html에 연결된 각 파일을 모두 로드하는 것이 아니라, 여기서 필요한 코드만을 분할함으로서, 초기 로드 시간을 줄이는 것이 핵심입니다.
즉 , Index.html 을 예시로 들면, Header, Footer, Body, Aside 와 같은 여러 영역이 존재하고 각 영역마다 적용되는 JavaScript, CSS가 있다면, 이를 조각화로 나눔으로서, 필요한 영역만을 로드할 수 있도록 처리하여 효율성을 올리는 기술입니다.
2. Module-Bundler 의 종류 및 장단점
RequireJS 를 시작으로 사용되는 Library 는 여러 종류가 있지만, 장단점이 존재합니다.
대표적으로 Webpack 의 경우 사용자가 많고, 각 라이브러리에 추가적으로 플러그인이나 로더가 존재하지만, 이에 맞게 활용하기 위해서는 장단점을 알아야 적용이 가능할 겁니다.
아래의 실제 기본 사용예시는 Webpack 을 기준으로 할 예정이지만, 각 라이브러리의 특징을 알아보시는 것도 향후 사용에 도움이 되는 라이브러리가 어떤 것인지 식별하는데 도움이 될 거라고 생각됩니다
장점 | 단점 | |
RequireJS | 1. 비동기식 모듈 로딩을 필요할 때에만 모듈을 로드함으로써 성능을 향상합니다. 2. 모듈 간 의존성을 지정할 수 있어 올바른 순서로 로드되도록 조정 가능 3. 다중 위치에서 모듈을 로드할 수 있도록 구성이 가능하므로 타 라이브러리와 통합이 손쉽게 사용이 가능 4. text, domReady 플러그인을 지원하여 기능을 확장할 수 있습니다. 이외에도 다른 플러그인을 지원 5. 쉼핑 기능을 통해 AMD(Asynchronous Module Definition) 이 아닌 모듈을 AMD 코드와 함께 사용가능 |
1. ES6 Module 을 지원하지 않음 2. 작은 프로젝트인 경우 RequireJS 는 오버헤드를 일으킬 수 있음 3. AMD Formatting 에 익숙하지 않을 경우 접근이 어려움 4. 의존성 흐름 추적이 어려움 5. RequireJS 는 최초 구성에 시간이 많이 소요됨 |
Webpack | 1. 다양한 유형의 모듈과 파일 지원 2. 코드 분할 및 지연로딩을 지원하여 성능을 개선함 3. 다양한 플러그인과 로더를 지원 4. 유연하게 구성할 수 있고 사용자 정의 가능 |
1. 구성이 단순하지 않은 편이고 러닝커브가 높음 2. 큰 프로젝트일 경우 느리게 빌드될 수 있고 별도의 최적화가 필요할 수 있음 3. 일부 플러그인 및 로더는 사용이 원할하지 않을 수 있음 |
Rollup | 1. 라이브러리 생성을 위해 설계되었고, Tree-Shaking 기능에 최적화 2. 최소한의 오버헤드로 효율적인 빌드를 지원 3. 다양한 유형의 모듈과 파일 지원 |
1. 플러그인 및 로더의 제한된 지원 2. 복잡한 프로젝트일 경우 구성이 어려움 |
Parcel | 1. 설정 없이 빠르게 사용 가능 2. 다양한 유형의 파일 지원 3. 자동 캐싱을 지원함으로서 효율적 빌드 지원 4. 개발 서버를 제공하여 핫 모듈 교체 지원 |
1. 구성 가능한 커스텀 옵션이 제한적 2. 플러그인 및 로더의 제한된 지원 3. 대형 프로젝트일수록 느릭 속도 |
Browserify | 1. 간단하고 쉬운 사용법 2. CommonJS 모듈 지원 3. 중소규모 프로젝트에 적합한 성능과 빌드시간 지원 |
1. 최신 JavaScript / ES6 모듈의 지원이 제한적임 2. 구성 가능한 커스텀 옵션이 제한적 |
Brunch | 1. 간단하고 쉬운 사용법 2. 최소한의 구성으로 효율적인 빌드 지원 3. 다양한 파일을 지원하고 라이브리로딩이 가능한 개발 서버 제공 |
1. 구성 가능한 커스텀 옵션이 제한적 2. 플러그인 및 로더의 제한된 지원 |
FuseBox | 1. 높은 최적화 기능으로 빠른 빌드와 효율적 코드 지원 2. 다양한 유형의 파일과 모듈 지원 3. 핫 모듈 교체가 가능한 개발서버 제공 |
1. 플러그인 및 로더의 제한된 지원 2. 구성이 복잡하나 문서화가 완벽하지 않음 |
3. WebPack 사용방법
별도의 파일은 없이 최소한의 구성으로 사용법을 작성해보도록 하겠습니다.
당연히 NPM 을 사용하여 webpack 을 사용하기 위해 필요한 리소스를 설치해야 합니다.
예제로, 하나의 플러그인 Html-Webpack-Plugin 을 같이 적용해보도록 하겠습니다.
npm install webpack webpack-cli html-webpack-plugin
설치를 하게 되면, 설치 경로에 이제 webpack 을 구성하기 위해서 구성파일을 생성해야 합니다.
생성은 마우스로 직접 생성하셔도 되고, CLI 로 아래의 명령어를 이용하여 생성하셔도 좋습니다.
npx webpack --config webpack.config.js
생성을 하게 되면, 아래의 규칙으로 작성이 필요합니다.
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: '',
output: {
path: '',
filename: '',
},
module: {
rules: [
{
test:
exclude:
use: {
loader: '',
options: {
presets: ['']
}
}
},
{
test: ,
use: ['']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: ''
})
],
devServer: {
contentBase: '',
port: '',
}
}
먼저 const 로 경로 지정을 위한 path, 그리고 사용하고자 하는 플러그인을 가져와야 합니다.
위에서는 경로지정을 위한 내장모듈인 Path, 그리고 예시로 사용하게 될 플러그인으로 HtmlWebpackPlugin 을 가져옵니다.
만약 별도의 플러그인을 더 가져올 예정이라면 그에 맞게 모두 가져와야 합니다.
그리고 module.exports method 를 사용하여 Webpack Configuration 을 내보낼 내용을 담아야 합니다.
이는 각각 아래의 규칙으로 담는것이 일반적입니다.
- Name : Webpack 구성의 이름을 정의합니다
- mode : Webpack 의 빌드 모드를 정의합니다.
- resolve : Webpack 이 모듈을 요청할 때, 어떠한 파일의 확장자를 지정할 지 사용됩니다. 일반적으로 지정하지 않는 다면, Javascript 파일인 ".js", 그리고 ".json" 파일이 정의되고, 필요한 경우 아래의 예시처럼 직접 지정해야 합니다.
resolve: {
extensions: ['.js', '.jsx', '.html', '.css'],
},
- Entry : Webpack 이 빌드할때의 시작점을 지정합니다. 즉 여기서 지정한 파일이 webpack 빌드의 시작점이 되게 됩니다.
- module : 다른 종류의 모듈을 처리하는 방법을 설정합니다. React 에서의 예를 들어본다면, "JSX" 확장자의 파일은 Babel 을 통해 코드가 브라우저에 호환될 수 있도록 JavaScript 로 변환이 되어야 하니, 아래의 예시처럼 Babel-preset 을 이용하여, ES5/6 JavaScript 로 변환해야 합니다.
module : {
rules : [
{
test : /\.jsx?/,
loader : "babel-loader",
options : {
presets: ["@babel/preset-env","@babel/preset-react"],
}
}
],
},
- plugins : 사용하고자 하는 플러그인의 배열을 지정합니다. 여기에는 두가지의 옵션을 지정해야 합니다. template, filename 을 지정해야 합니다. 여기서 Template 의 경우 이미 있는 파일 중 어떠한 파일을 사용할 것인지를 지정하고, 지정된 파일을 Webpack 으로 번들화 할 때, 사용할 이름을 "Filename" 에 지정해야 합니다. 아래의 예시는 "./src/index.html" 파일을 사용하고, 변환된 파일명은 "Hynn.html"로 지정하는 설정의 예시입니다.
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'Hynn.html',
}),
],
}
- output : 이제 모듈번들러가 완료되면, 완료된 파일을 출력해야 합니다. 여기서 지정함으로서 출력된 파일의 이름 및 경로를 지정해야 합니다. 단 여기서 output 의 경로는 절대경로로 지정해야 합니다. 하지만 직접 작성하기에는 복잡할 수 있기에, 간편하게 내장모듈인 "Path"를 활용해서 절대경로를 지정할 수 있습니다. 아래는 예시입니다. 두가지 예시 중 더 손이 가는쪽'으로 작성하시면 좋을 거 같습니다.
Option1)
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
},
}
Option2)
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
}
- devServer : Webpack 에 내장된 개발 서버를 구성할 때 사용됩니다. 이 기능은 필수적으로 사용하는 기능은 아니지만 작성한 코드를 로컬에서 테스트할 때 사용되며, 라이브 리로딩, 핫 모듈 교체 및 라우트 기능을 지원합니다. 여기서 각각의 Method 의 정의는 아래와 같습니다.
- static : 정적 컨텐츠가 될 루트 디렉토리를 지정합니다. 역시 절대 경로로 설정해야 하므로, 예시에서는 위와 같이 path를 사용하여 지정합니다.
- compress : 리소스를 gzip 압축을 활성화 합니다. 이 옵션을 활성화 하면 네트워크를 통해 전송되는 데이터의 양을 줄일 수 있습니다.
- port : 개발서버가 수신할 포트를 지정합니다. 설정하지 않을 경우 기본 포트는 8080으로 지정됩니다.
- hot : 핫 모듈 교체를 활성화합니다. "true" 로 활성화 되어 있을 경우, 코드 변경사항이 반영되어 전체 페이지를 다시 로드하지 않아도 됩니다.
- historyapiFallback : static 컨텐츠와 일치하지 않는 모든 경로에 대해 index.html 로의 대체를 활성화 하는 기능입니다. 일반적으로 React 같은 프레임워크를 사용하는 클라이언트 측 라우팅에 도움이 됩니다.
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 3000,
hot: true,
historyApiFallback: true,
},
이제 이러한 Webpack 을 설정했다면, 간단하게 사용이 가능합니다.
아래의 명령어를 터미널에 입력하면, webpack 이 실행됩니다.
npx webpack
다음 포스팅에서는 React 에서 CSS를 어떻게 적용하는지에 대해서 알아보도록 하겠습니다.
감사합니다.
'개발공부일지 > React' 카테고리의 다른 글
React - CRA(Create-React-App) 사용하기 (0) | 2023.03.15 |
---|---|
React - StyledComponent / CSS-Loader (0) | 2023.03.15 |
React - 합성/상속 알아보기 (0) | 2023.03.07 |
React - 상태 끌어올리기 (Lifting State up) (0) | 2023.03.06 |
React - Form 사용하기 (0) | 2023.03.06 |
댓글