webpack 이 세상에 나온 건 꽤 되었다. 원리나 컨셉은 단순한데 (모든 js 파일이나 기타 등등을 묶어서 하나로 만들어준다~) 그것을 설정하는 webpack.config.js 의 내용은 꽤나 어렵다. 그러면서 리액트를 사용할 때 쓰는 CRA나 NEXT.JS의 경우 zero config 를 지향하다보니 어지간한 경우가 아니면 따로 webpack 설정을 할 필요가 없었다. 하지만 최근에 회사에서 어떤 프로젝트 하나를 하게 되었는데 (다행히 엔드유저용은 아님) 이게 도무지 webpack 을 모르면 할 수 없는 내용이라 일단 인프런에 있는 강의를 하나 사서 듣고 그에 연관된 https://jeonghwan-kim.github.io/series/2019/12/10/frontend-dev-env-webpack-basic.html 내용을 같이 보기 시작했다.
일단 node.js 의 문법으로 되어있다. es6의 import 부터 시작하는 문법은 리액트를 다뤘다면 필수로 만지기 때문에 낯설지 않지만 webpack.config.js 는 node.js 에서 돌기 때문에 node.js 문법이 필수다. 나는 깊이가 없는지라 아무리 봐도 비슷한 듯 서로 다른 이 문법이 참 요상하다.
const path = require('path');
export.modules = {
mode: '', // 'development', 'production', 'test' 정도가 있는 것 같다. 필수요소
entry: { // webpack 을 말기(?) 시작하는 파일 설정이다. 객체로 작성하며 하나일 수도 있고 여러 개 일 수도 있다. 역시나 필수요소
main: '',
loadWebViz: '',
},
output : { // webpack 으로 말아서 떨꿀 곳을 지정하는 곳, 객체로 작성하며 필수요소
filename : '[name].js', // [name] 이라는 부분에 entry의 key가 들어가서 파일이 만들어진다.
path: path.resolve('./dist') // 이건 node.js 의 문법이란다. 이걸 모르니 대충 파일 떨구는 곳을 지정하는구나.. 라고 알겠는데 뭔지는 도무지 모르는 상태였다.
}
}
이정도를 기본으로 삼고 있다. 파일이 뭔가 설정정보를 담고 있는 json 과 비슷하기도 하지만 나중에 loader 나 plugins 부분에 가면 생성자 함수도 들어가고 난리도 아니다. 역시나 깊이가 없는 나의 문제이지만 왜 파일을 떨구는 설정의 key 값은 output 인데 webpack 을 말기 시작하는 부분을 설정하는 key 값은 input 이 아니고 entry 인지 여전히 단순무식하게 궁금하다. (사실 그 원리를 생각하면 entry 가 맞긴한데 말이다.)
그래도 여기까지는 어느정도 모양이 비슷하기도 한데 그 아래에 작성하는 loader 나 plugins 에서는 더 미치는 내용들이 나온다. 미치는 내용의 기준은 어디까지나 깊이가 없고 영어가 짧은 필자의 기준에서이다.
const path = require("path");
export.modules = {
mode: '',
entry: {
main: '',
loadWebViz: '',
},
output : {
filename : '[name].js',
path: path.resolve('./dist'),
},
module: { // 갑자기 모듈이라는 키가 등장한다.
rules: [ // rules는 뭐지? 그리고 갑자기 배열이 등장한다?
{ // 그리고 또 객체 등장
test: /\.css$/, // 정규식이 등장한다. 이것은 설마 정규식을 들이댈 때 쓰는 그 test?
use: [ // 또 배열이 나옴
'style-loader', 'css-loader' // 한번은 들어봤을 법한 로더들의 이름이 나오기 시작한다. 아. css 파일을 읽어들이는 로더인가보구나. 이거 없으면 webpack 은 돌다 에러를 뱉고 서버린다. 순서는 배열에 적힌 순서의 반대로 실행된다.
],
},
{
test: /\.(jpg|png)$/,
loader: 'url-loader', // 위에 없던 키가 튀어나온다.
options: {
name: '[name].[ext]?[hash]', // 출력파일에 이름규칙을 설정한다.
limit: 20000, // 20kb 보다 작으면 이미지들을 죄다 base64 인코딩으로 바꾼다.
},
},
],
},
}
갑자기 처음보는 module이 튀어나오더니 rules의 경우는 또 배열로 그 아래에 로더별 설정을 객체로 감싸서 받는다(....) 이런 모양새가 너무 당황스러웠는데 돈내고 인강을 사서 보니까.. 그냥 외우는 게 속편한 것 같더라. 신기한 것은 url-loader 의 경우, options 부분이 없으면 그냥 use 라는 key에 배열로 로더 이름을 올리면 된다. 뭔가 좀 일관성이 없어보인다고 생각하는데... 왠지 엄청나게 심오한 컨셉이 있을 것이지만 내가 영어가 짧아서 공식문서를 잘 들여다 보지 못해서 그런 깊은 뜻을 이해하지 못하는게 아닐까 싶다. 그리고 로더를 불러오는 부분이 보통 require로 땡겨놓고 변수를 넣는 것이지 않을까 라고 생각했으나 그런 과정은 없고 그냥 npm으로 설치해놓고 문자열로 부르면 된다. 더 신기한 것은 url-loader 에서 설정한 용량을 초과하는 경우에는 설정에는 없는(그러나 설치는 해놓은) file-loader가 작동해서 알아서 잘 처리해준다고 한다(...) 그래도 여기까지는 그러려니 했다.
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
export.modules = {
mode: '',
entry: {
main: '',
loadWebViz: '',
},
output : {
filename : '[name].js',
path: path.resolve('./dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(jpg|png)$/,
loader: 'url-loader',
options: {
name: '[name].[ext]?[hash]',
limit: 20000,
},
},
],
},
plugins: [ // 지금까지 이 depth에서 설정한 녀석들은 다 객체나 문자였는데 갑자기 배열이 나온다.
new webpack.BannerPlugin({
banner: () => `빌드날짜 : ${new Date().toLocaleDateString()}`,
}),
new HtmlWebpackPlugin({
template : './src/index.html',
}),
],
}
plugins 부분에서 제일 당황했다. 갑자기 설정의 값을 받는 부분이 배열이 된다. 왜 이런 식인지 도무지 모르겠으나 역시나 외워버리기로 한다. 일을 해야하니까..
아직 인강을 사서 33% 정도 밖에 못보고 있는데 계속 보고 실습하는대로 틈틈히 복습차원에서 기록을 남기고자 한다.