MiniCssExtractPlugin
스타일시트가 점점 많아지면 하나의 자바스크립트 결과물로 만드는 것이 부담일 수 있다.
번들 결과에서 스타일시트 코드만 뽑아서 별도의 CSS 파일로 만들어 역할에 따라 파일을 분리하는 것이 좋다.
브라우저에서 큰 파일 하나를 내려받는 것보다, 여러개의 작은 파일을 동시에 다운로드하는 것이 더 빠르다.
최종 결과물이 CSS파일 하나, JS파일 하나 이렇게 나오는 것이 좋다.
개발 환경에서는 CSS를 하나의 모듈로 처리해도 상관없지만 production 환경에서는 분리하는 것이 효과적이다.
MiniCssExtractPlugin 은 CSS를 별도 파일로 뽑아내는 플러그인이다.
이 플러그인 또한 써드파티 플러그인이기 때문에 설치해야된다.
npm i -D mini-css-extract-plugin
// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: "development",
entry: {
main: "./src/app.js"
},
output: {
path: path.resolve('./dist'),
filename: "[name].js" // name - 위에 main 키네임을 가져온다.
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
],
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
// publicPath: './dist',
name: '[name].[ext]?[hash]', // name - 원본파일이름
limit: 20000, // 20kb
}
}
]
},
plugins: [
new webpack.BannerPlugin({
banner: `
Build Date: ${new Date().toLocaleString()}
Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')}
Author: ${childProcess.execSync('git config user.name')}
`
}),
new webpack.DefinePlugin({
TWO: JSON.stringify('1+1'),
'api.domain': JSON.stringify('http://dev.api.domain.com')
}),
new HtmlWebpackPlugin({
template: './src/index.html',
templateParameters: {
env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
},
minify: process.env.NODE_ENV === 'production' ? {
collapseWhitespace: true,
removeComments: true,
} : false
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css' // 원본파일 이름 (이렇게 설정 안하면 해시값으로 내보냄), 근데 결국 js파일의 원본네임이니까 위의 main 키네임 가져오는 건 같음
}),
]
}
이 플러그인은 자바스크립트에서 CSS를 뽑아내는 과정을 추가하는 것이기 때문에 굳이 개발 환경에서는 안해도 된다. 개발환경에서는 자바스크립트 파일 하나로 빌드하는 것이 좀 더 빨리 빌드될 것이다.
const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: "development",
entry: {
main: "./src/app.js"
},
output: {
path: path.resolve('./dist'),
filename: "[name].js" // name - 위에 main 키네임을 가져온다.
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
],
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
// publicPath: './dist',
name: '[name].[ext]?[hash]', // name - 원본파일이름
limit: 20000, // 20kb
}
}
]
},
plugins: [
new webpack.BannerPlugin({
banner: `
Build Date: ${new Date().toLocaleString()}
Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')}
Author: ${childProcess.execSync('git config user.name')}
`
}),
new webpack.DefinePlugin({
TWO: JSON.stringify('1+1'),
'api.domain': JSON.stringify('http://dev.api.domain.com')
}),
new HtmlWebpackPlugin({
template: './src/index.html',
templateParameters: {
env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
},
minify: process.env.NODE_ENV === 'production' ? {
collapseWhitespace: true,
removeComments: true,
} : false
}),
new CleanWebpackPlugin(),
...(process.env.NODE_ENV === 'production' ? [
new MiniCssExtractPlugin({
filename: '[name].css' // 원본파일 이름 (이렇게 설정 안하면 해시값으로 내보냄), 근데 결국 js파일의 원본네임이니까 위의 main 키네임 가져오는 건 같음
}),
] : []
)
]
}
...
나머지 연산자로 위와 같이 정의해주면 환경변수에 따라 MiniCssExtractPlugin를 활성화 하거나 활성화를 안 시킬 수 있다.
...
나머지(스프레드) 연산자는 말 그대로 배열을 펼치는 연산자이기 때문에 ...()
소괄호 안에 배열을 넣어줘야된다.
MiniCssExtractPlugin 이 플러그인은 다른 플러그인과 다르게 로더 설정도 추가해야된다.
// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: "development",
entry: {
main: "./src/app.js"
},
output: {
path: path.resolve('./dist'),
filename: "[name].js" // name - 위에 main 키네임을 가져온다.
},
module: {
rules: [
{
test: /\.css$/,
use: [
process.env.NODE_ENV === 'production' ?
MiniCssExtractPlugin.loader :
'style-loader',
'css-loader'
],
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
// publicPath: './dist',
name: '[name].[ext]?[hash]', // name - 원본파일이름
limit: 20000, // 20kb
}
}
]
},
plugins: [
new webpack.BannerPlugin({
banner: `
Build Date: ${new Date().toLocaleString()}
Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')}
Author: ${childProcess.execSync('git config user.name')}
`
}),
new webpack.DefinePlugin({
TWO: JSON.stringify('1+1'),
'api.domain': JSON.stringify('http://dev.api.domain.com')
}),
new HtmlWebpackPlugin({
template: './src/index.html',
templateParameters: {
env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
},
minify: process.env.NODE_ENV === 'production' ? {
collapseWhitespace: true,
removeComments: true,
} : false
}),
new CleanWebpackPlugin(),
...(process.env.NODE_ENV === 'production' ? [
new MiniCssExtractPlugin({
filename: '[name].css' // 원본파일 이름 (이렇게 설정 안하면 해시값으로 내보냄), 근데 결국 js파일의 원본네임이니까 위의 main 키네임 가져오는 건 같음
}),
] : []
)
]
}
위와 같이 로더에도 process.env.NODE_ENV
환경변수 값에 따라 어떤 로더를 쓸지 분기처리한다.
NODE_ENV=production npm run build
그리고 노드 환경변수를 production
으로 주고 빌드 명령어를 실행해보자.
그럼 위와 같이 main.css
파일이 생성된 것을 확인하실 수 있다.
그리고 dist/index.html
을 보시면
이렇게 main.css
도 link가 걸려있는 것을 확인할 수 있다.