이전 포스팅이에서 모듈 시스템을 사용하기 위해 webpack 이 필요한 이유와 그 설정 방법에 대해 알아보았다. 이번에는 CSS를 웹팩환경에서 사용하는 방법과 기타 유용한 플러그인 및 설정에 대해 알아본다.
<link>
태그를 이용해서 HTML 파일에 정적으로 CSS를 로드해보자. 그리고 dev server를 구동해보자
// index.html
...
<link rel="stylesheet" src="src/main.css" />
...
이럴 경우 이런 에러를 발견하게 된다.
Cannot GET src/main.css..
이 에러의 원인은 webpack.config.js
에서 devSever
세팅 시, 정적 파일로 사용할 디렉토리를 public
으로만 지정하였기 때문에 src에 있는 main.css를 읽지 못하는 것이다.
따라서 이 문제를 간단하게 해결하기 위해서는 static 배열에 ‘src’를 추가하면 되지만, 이럴 경우 devSever가 public 내에 번들링 된 파일 이외의 자원을 참조하는 문제가 발생한다.
devServer: {
static: ['public'],
port: 3000,
compress: true,
client: {
logging: 'info',
overlay: true,
},
}
이런 문제를 해결하기 위해, Webpack은 CSS와 관련된 다음 2가지의 loade를 제공한다.
css-loader는 css 내의 @import 또는 url()로 된 문법을 import/require로 변환하거나, css 파일을 js 형태로 변환하는 역할을 한다. 따라서 해당 로더를 사용하면 js 파일에 css 파일을 import 하여 사용할 수 있다.
👉 사용방법
npm install --save-dev css-loader
// file.js
import css from "file.css";
...
이 덕분에 각 js
파일과 css
파일을 관심사에 따라 하나로 묶어서 관리하고, 해당 js
파일에 css
파일을 불러와 사용할 수 있다. 물론 css
는 스코프가 없기 때문에, 클래스 네이밍 등에 신경써야 한다. (이는 css Module
또는 styled-components
를 통해 해결할 수 있다)
스타일 로더는 동적으로 CSS를 DOM에 삽입하여 CSS가 적용되도록 역할을 한다.즉, js 파일이 로드 되고 CSS import 구문을 만나면 <style>
태그 하위에 해당 css
코드를 동적으로 삽입한다.
물론 개발 시에 굉장히 편리하지만, CSS를 동적으로 삽입하는 것은 사용자 관점에서 굉장히 비효율적이고 느린 방법이다.
👉 사용방법
npm install --save-dev style-loader
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
};
이 때, style-loader
가 먼저 오고 css-loader
가 오는 순서에 주의하자
스타일 로더는 개발 시 편리하지만 배포를 할 경우 성능 이슈가 발생한다. 위에서 언급했듯이 동적으로 CSS를 삽입하기 때문에 배포를 할 경우 정적인 CSS 파일을 생성할 필요가 있다. 이를 위한 플러그인이 miniCssExtractPlugin
이다.
MiniCssExtractPlugin | webpack
이 플러그인의 설명을 보면 CSS를 별도의 파일로 추출한다. 즉, CSS를 import 한 JS 파일 당 하나의 CSS파일을 생성한다.
👉 사용방법
npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
rules: [
...
{
test: /\.css$/i,
use: [
// 개발 시에는 style-loader를 사용하고 배포할 경우 해당 플러그인의 loader를 사용
development ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
],
},
...
]
}
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(ROOT_DIR, 'public/index.html'),
title: '랜덤 카운트 업 - React Count Up',
}),
// 배포할 경우에만 해당 플러그인 사용
production &&
new MiniCssExtractPlugin({
// filename 옵션을 통해 빌드할 파일 이름과 위치를 지정
filename: 'css/[name].css',
}),
].filter(Boolean),
miniCssExtractPlugin
으로 생성된 CSS 정적 파일은 압축이나 불필요한 코드가 포함되어 있는 등 최적화가 되지 않았다. 따라서 빌드 시, 해당 CSS 파일을 다른 번들링 파일처럼 최적화할 수 있는 도구가 필요하다
CssMinimizerWebpackPlugin | webpack
👉 사용방법
npm install css-minimizer-webpack-plugin --save-dev
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
...
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(ROOT_DIR, 'public/index.html'),
title: '랜덤 카운트 업 - React Count Up',
}),
...
production && new CssMinimizerPlugin(),
...
].filter(Boolean),
optimization: production && {
minimize: true,
minimizer: [
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
'default',
{
discardComments: { removeAll: true },
},
],
},
}),
],
}
minimize : true
development 모드에서도 최적화를 하기 위한 옵션minimizerOptions
(Link)preset
설정에 대한 자세한 옵션 보기 (Link)discardComments
: 주석 제거 옵션CSS 압축을 위해서 CssMinimizerWebpackPlugin을 사용하였더니, 기존에 잘 압축되었던 JS 파일의 최적화가 되지 않는 문제가 발생한다. 원래는 JS 파일은 Webpack 최신 버전에서는 별도의 플러그인 없이 자동으로 최적화를 해주었지만, CssMinimizerWebpackPlugin을 사용하기 위해서는 별도의 JS 압축 플러그인이 필요하다
👉 사용방법
npm install terser-webpack-plugin --save-dev
const TerserPlugin = require("terser-webpack-plugin");
...
optimization: production && {
minimize: true,
minimizer: [
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
'default',
{
discardComments: { removeAll: true },
},
],
},
}),
new TerserPlugin()
],
}
빌드 디렉토리에 특정 파일 또는 폴더의 자원을 복사해주는 플러그인
devServer의 static 옵션이 public 폴더일 경우, 해당 폴더 내의 index.html 및 icon 등에 필요한 image 자원이 위치해 있다. 따라서 개발 시에는 public 폴더로 bundle되어 문제가 되지 않지만, build 상황의 경우 entry로 설정한 src 하위 파일만 번들되어 build 폴더가 생성되므로 필요한 자원을 수동으로 일일히 build 폴더에 옮겨 주어야 한다.
이런 문제를 해결하기 위해 빌드 시, public 폴더 내의 있는 파일들을 build 폴더 내에 복사해주는 플러그인이 유용하게 사용된다.
👉 사용방법
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "source", to: "dest" }, // from 위치에서 to로 복사할 경로를 지정
],
}),
],
};
https://github.com/webpack-contrib/webpack-bundle-analyzer
번들링 된 파일의 크기를 시각적으로 확인할 수 있는 도구
번들링 된 파일의 크기를 확인하고 지나치게 큰 파일은 없는지 확인하여 적절히 코드 분할이나 최적화하는데 도움을 준다.
👉 사용방법
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
Webpack을 통해서 빌드할 경우 속도를 측정하여 CLI로 알려주는 도구
// webpack.config.js
resolve: {
extensions: ['.jsx', '.js', '.json', '.wasm'],
alias: {
'@': path.resolve(ROOT_DIR, 'src'), // alias를 통해 경로에 대한 별칭 지정 가능
},
},
// root에 jsconfig.json 생성
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["**/*.js", "**/*.jsx"],
"exclude": ["node_modules", "public"]
}
// test.js
import { test } from '@/test.js' // src/test.js와 동일