자주 사용하는 웹팩 플러그인
개발하면서 플러그인을 직접 작성할 일은 거의 없었다. 웹팩에서 직접 제공하는 플러그인을 사용하거나 써드파티 라이브러리를 찾아 사용하는데 자주 사용하는 플러그인에 대해 알아보자.
BannerPlugin
번들 결과물에 빌드 정보나 커밋 버전같은 걸 추가할 수 있다.
- webpack.config.js
1
2
3
4
5
6
7
8
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.BannerPlugin({
banner: '이것은 배너 입니다',
})
]
생성자 함수에 전달하는 옵션 객체의 banner 속성에 문자열을 전달한다. 웹팩 컴파일 타임에 얻을 수 있는 정보, 가령 빌드 시간이나 커밋정보를 전달하기위해 함수로 전달할 수도 있다.
1
2
3
4
5
6
7
8
9
10
plugins: [
// new MyWebpackPlugin(),
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')}
`
})
]
배너 정보가 많다면 별로 파일로 분리하자.
1
2
3
const banner = require("./banner.js")
new webpack.BannerPlugin(banner)
빌드 날짜 외에서 커밋 해쉬와 빌드한 유저 정보까지 추가해 보자.
- banner.js
1
2
3
4
5
6
7
8
9
10
11
const childProcess = require("child_process")
module.exports = function banner() {
const commit = childProcess.execSync("git rev-parse --short HEAD")
const user = childProcess.execSync("git config user.name")
const date = new Date().toLocaleString()
return (
`commitVersion: ${commit}` + `Build Date: ${date}\n` + `Author: ${user}`
)
}
빌드한뒤 플러그인이 처리한 결과는 다음과 같다.
DefinePlugin
어플리케이션은 개발환경
과 운영환경
으로 나눠서 운영한다. 가령 환경에 따라 API 서버 주소가 다를 수 있다.
같은 소스 코드를 두 환경에 배포하기 위해서는 이러한 환경 의존적인 정보를 소스가 아닌 곳에서 관리하는 것이 좋다. 배포할 때마다 코드를 수정하는 것은 곤란하기 때문이다.
웹팩은 이러한 환경 정보를 제공하기 위해 DefinePlugin
을 제공한다.
- webpack.config.js
1
2
3
4
5
const webpack = require("webpack")
export default {
plugins: [new webpack.DefinePlugin({})],
}
빈 객체를 전달해도 기본적으로 넣어주는 값이 있다. 노드 환경정보인 process.env.NODE_ENV 인데 웹팩 설정의 mode에 설정한 값이 여기에 들어간다. “development”를 설정했기 때문에 어플리케이션 코드에서 process.env.NODE_ENV 변수로 접근하면 “development” 값을 얻을 수 있다.
- app.js
1
console.log(process.env.NODE_ENV) // "development"
이 외에도 웹팩 컴파일 시간에 결정되는 값을 전역 상수 문자열로 어플리케이션에 주입할 수 있다.
1
2
3
new webpack.DefinePlugin({
TWO: "1+1",
})
TWO라는 전역 변수에 1+1 이란 코드 조각을 넣었다. 실제 어플리케이션 코드에서 이것을 출력해보면 2가 나올 것이다.
- app.js
1
console.log(TWO) // 2
코드가 아닌 값을 입력하려면 문자열화 한 뒤 넘긴다.
1
2
3
4
5
6
plugins: [
new webpack.BannerPlugin(banner),
new webpack.DefinePlugin({
TWO: JSON.stringify('1+1')
})
]
- app.js
1
console.log(TWO) // '1+1'
만약 객체를 넣고 싶다면 아래와 같이 입력하면 된다.
1
2
3
4
5
6
7
plugins: [
new webpack.BannerPlugin(banner),
new webpack.DefinePlugin({
TWO: JSON.stringify('1+1'),
'api.domain': JSON.stringify('http://dev.api.domain.com')
})
]
빌드 타임에 결정된 값을 어플리이션에 전달할 때는 이 플러그인을 사용하자.
HtmlWebpackPlugin
이번엔 써드 파티 패키지에 대해 알아보자. HtmlWebpackPlugin은 HTML 파일을 후처리하는데 사용한다. html 파일을 번들링 과정에 포함한다고 생각하면 된다. 그러면 빌드 타임의 값을 넣거나 코드를 압축할수 있다.
먼저 패키지를 다운로드 하자.
1
$ npm install -D html-webpack-plugin
이 플러그인으로 빌드하면 HTML파일로 아웃풋(dist 티렉토리)에 생성될 것이다. index.html 파일을 src/index.html
로 옮긴뒤 다음과 같이 작성해 보자.
- src/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 로딩 스크립트 제거 -->
<!-- <script src="../dist/main.js"></script>-->
</body>
</html>
타이틀 부분에 ejs 문법을 이용하는데 <%= env %> 는 전달받은 env 변수 값을 출력한다.
HtmlWebpackPlugin
은 이 변수에 데이터를 주입시켜 동적으로 HTML 코드를 생성한다.
뿐만 아니라 웹팩으로 빌드한 결과물을 자동으로 로딩하는 코드를 주입해 준다. 때문에 스크립트 로딩 코드도 제거했다.
- webpack.config.js
1
2
3
4
5
6
7
8
9
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html', // 템플릿 경로를 지정
})
]
}
빌드를 실행해보면 dist/index.html
파일이 생성되고 안에 자동적으로 main.js
를 로딩하는 스크립트파일이 포함되어 있다.
HtmlTeamplatePlugin
플러그인을 사용하면 좀 더 유동적으로 html을 만들어낼 수 있다. 만약 개발 버전일 경우 <title>Document 개발용</title>
를 표시해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document <%= env %></title>
</head>
<body>
<!-- 로딩 스크립트 제거 -->
<!-- <script src="../dist/main.js"></script>-->
</body>
</html>
이제 NODE_ENV=development npm run build
명령어를 실행해서 빌드를 하면 되는데 아래와 같은 오류가 나타날 경우가 있다.
그럴 경우엔 환경 변수 PATH에 다음과 같이 경로를 하나 추가해주자. 참고
그러면 정상적으로 아래와 같이 빌드된 결과에 (개발용)
이란 문구가 찍힌걸 확인할 수 있다.
반대로 NODE_ENV=production npm run build
으로 실행하면 해당 문구가 안나타나는걸 확인할 수 있다. 위와 같은 방식으로 휴먼 에러를 줄일 수가 있다.
이것 뿐만 아니라 html을 압축하고 주석을 제거하는 기능도 있다.
1
2
3
4
5
6
7
8
9
10
11
new HtmlWebpackPlugin({
template: './src/index.html',
templateParameters: {
env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
},
minify: {
collapseWhitespace: true, // 빈칸 제거
removeComments: true, // 주석 제거
}
})
운영 환경에서만 minify 옵션을 키도록 하는게 편하기에 아래와 같이 수정할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
new HtmlWebpackPlugin({
template: './src/index.html',
templateParameters: {
env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
},
minify: process.env.NODE_ENV === 'production' ? {
collapseWhitespace: true, // 빈칸 제거
removeComments: true, // 주석 제거
} : false
})
CleanWebpackPlugin
CleanWebpackPlugin 은 빌드 이전 결과물을 제거하는 플러그인이다.(dist 폴더를 빌드 시작 전에 싹 날려주는)
해당 플러그인은 외부에서 디펜던시를 가져와서 사용해야 하므로 다음 명령어를 이용해 설치해야 한다.
1
$ npm install -D clean-webpack-plugin
빌드 결과물은 아웃풋 경로에 모이는데 과거 파일이 남아 있을수 있다. 이전 빌드내용이 덮여 씌여지면 상관없지만 그렇지 않으면 아웃풋 폴더에 여전히 남아 있을 수 있다.
임시로 아웃풋 폴더에 foo.js 파일을 만든 후 다시 빌드해 보자…… 파일이 남아 있을 것이다.
아래와 같이 해당 플러그인을 적용하면 깔끔하게 사라지는 것을 확인할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
plugins: [
// new MyWebpackPlugin(),
new webpack.BannerPlugin(banner),
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()
]
MiniCssExtractPlugin
스타일시트가 점점 많아지면 하나의 자바스크립트 결과물로 만드는 것이 부담일 수 있다. 번들 결과에서 스타일시트 코드만 뽑아서 별도의 CSS 파일로 만들어 역할에 따라 파일을 분리하는 것이 좋다. 브라우져에서 큰 파일 하나를 내려받는 것 보다, 여러 개의 작은 파일을 동시에 다운로드하는 것이 더 빠르다.
개발 환경에서는 CSS를 하나의 모듈로 처리해도 상관없지만 프로덕션 환경에서는 분리하는 것이 효과적이다. MiniCssExtractPlugin은 CSS를 별로 파일로 뽑아내는 플러그인이다.
먼저 패키지를 설치해주자.
1
$ npm install -D mini-css-extract-plugin
웹팩 설정을 추가한다.
- webpack.config.js
1
2
3
4
5
6
7
8
plugins: [
...
new CleanWebpackPlugin(),
...(process.env.NODE_ENV === 'production'
? [new MiniCssExtractPlugin({filename: '[name].css'})] // javascript 에서 css 파일을 뽑아내는 과정이기에 굳이 개발환경에서는 필요없다(Javascript 파일 하나로 빌드하는 것이 더 빠르다)
: []
)
]
프로덕션 환경일 경우만 이 플러그인을 추가했다. filename에 설정한 값으로 아웃풋 경로(dist)에 CSS 파일이 생성될 것이다.
개발 환경에서는 css-loader
에의해 자바스크립트 모듈로 변경된 스타일시트를 적용하기위해 style-loader
를 사용했다.
반면 프로덕션 환경에서는 별도의 CSS 파일으로 추출하는 플러그인을 적용했으므로 다른 로더가 필요하다. 즉, MiniCssExtractPlugin
에서 제공하는 별도의 로더를 사용해줘야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
process.env.NODE_ENV === "production"
? MiniCssExtractPlugin.loader // 프로덕션 환경
: "style-loader", // 개발 환경
"css-loader",
],
},
],
},
}
플러그인에서 제공하는 MiniCssExtractPlugin.loader
로더를 추가한다.
NODE_ENV=production npm run build
로 결과를 확인해보자.
main.css
파일이 생성되고 html 파일에서 불러들이는 것을 확인할 수 있다.
정리
BannerPlugin
: 번들링된 결과물 상단에 빌드 정보를 추가해서 번들 결과물이 정상적으로 배포되었는지 확인하기 위해 사용한다.DefinePlugin
: 빌드 타임에 결정되는 환경 변수를 애플리케이션단에 주입하기 위해 사용한다. 대표적으로 api 주소를 환경(prod, dev)에 따라 달리할때 사용한다.HtmlTemplatePlugin
: 그동안은 html 파일을 빌드 과정에 넣지 않았지만, 해당 플러그인을 빌드 과정에 넣어준다. 동적으로 생성되는 javascript와 css 그리고 빌드 타임에 결정되는 값들을 템플릿 파일에 넣어서 html 파일을 동적으로 만드는데 사용한다.CleanWebpackPlugin
: 빌드 시작 전마다 dist폴더를 삭제해준다.MiniCssExtractPlugin
: 번들된 자바스크립트 파일에서 스타일코드만 따로 뽑아내서 css 파일을 만들어주는 플러그인이다.