[Webpack] Basic Config Options

Marullo·2021년 3월 29일
post-thumbnail

1. Mode

mode: "production", // "production" | "development" | "none"

  • webpack build시 빌트인된 모드를 골라 최적화를 할 수 있다.
  • webpack에는 DefinePlugin이 있는데, 이것으로 webpack은 환경변수를 생성할 수 있다.

none 모드 : 아무것도 안함

development 모드(default)
process.env.NODE_ENV 환경변수를 생성하고 "development"라는 값을 할당해준다.
development 모드로 만들어진 번들 파일은 압축도 안되어 있고, 번들 파일에서 소스코드를 그대로 확인 할 수 있다.

production 모드
process.env.NODE_ENV 환경변수를 생성하고 "production"이라는 값을 할당해준다.
production 모드로 만들어진 번들 파일은 압축이 되어 있다.
(압축된 파일을 보면 각종 변수명이나 함수명이 이상한 문자로 줄여져있는 것을 볼 수 있다.)



2. Entry

entry: "./app/entry", // string | object | array

  • entry는 번들을 만드는 시작점(Dependency Graph의 루트 노드)을 의미한다.
  • entry 옵션에 경로를 설정해서, 시작점을 삼을 파일을 명시할 수 있다. (npx webpack 명령어를 사용할 때는 시작점이 ./src/index.js로 픽스되어 있다.)
  • A dynamically loaded module is not an entry point. 정적으로 로드되는 것만이 entry point가 될 수 있다.
  • HTML페이지 당 하나의 entry point만을 가질 수 있다. 즉, SPA 프로젝트에서는 Entry Point가 하나다.
  • SPA가 아니라면 다음과 같이 여러개의 entry point를 명시할 수 있다.
    entry: {
        home: './home.js',        
        about: './about.js',
        contact: './contact.js'
      }
    // 각 entry point들은 번들이 되어 `main.js`라는 이름으로 지정된 경로에 저장될 것이다.
    // 경로는 output 옵션에서 설정해주면 된다.

Bundle Filename 설정

  • 만약 main.js라는 이름으로 저장되는게 싫다면, filename을 지정해주면 된다.
    이건 output 옵션에서도 할 수 있으니 대충 보고만 지나가자.
    entry: {
        app: './app.js',
        home: { import: './contact.js', filename: 'pages/[name][ext]' },
        about: { import: './about.js', filename: 'pages/[name][ext]' }
    }

  • Entry chunk들은 자신이 사용하는 모듈을 저장하는데, DependOn 옵션을 사용하면, 한 entry chunk에서 다른 entry chunk로 모듈을 공유할 수 있다.
    //ex 1
    entry: {
        app: { import: './app.js', dependOn: 'react-vendors' },
        'react-vendors': ['react', 'react-dom', 'prop-types']
      }
    **react-vendor가 가지고 있는 세개의 모듈의 의존되어 있음을 나타낸다.** 
    **app이라는 entry chunk는 따로 저 세개의 모듈을 저장하지는 않는다.**

    //ex 2
    entry: {
        app: { import: ['./app.js', './app2.js'], dependOn: 'react-vendors' },
        'react-vendors': ['react', 'react-dom', 'prop-types']
      }
    **배열을 사용해서 여러개의 entry chunk가 react-vendor에 의존되어 있음을 나타낼 수도 있다.**


3. Output

얜 자잘한 옵션이 너무 많다. https://webpack.js.org/configuration/output/

번들링된 결과물을 저장할 path와 파일명을 지정할 수 있다.
(명시하지 않으면, ./dist/main.js에 저장된다.)

output: {
	  path: path.resolve(__dirname, 'dist'); //__dirname/dist의 경로에
	  filename: 'myBundle.js';               //myBundle.js의 이름으로 번들 생성
  }


4. Module

웹팩은 모든 파일을 모듈로 바라본다. 자바스크립트로 만든 모듈 뿐만아니라 스타일시트, 이미지, 폰트까지도 전부 모듈로 보기 때문에 import 구문을 사용하면 자바스크립트 코드 안으로 가져올수 있다.

이것이 가능한 이유는 웹팩의 로더(Loader) 덕분이다. 로더는 타입스크립트 같은 다른 언어를 자바스크립트 문법으로 변환해 주거나 이미지를 data URL 형식의 문자열로 변환한다. 뿐만아니라 CSS 파일을 자바스크립트에서 직접 로딩할수 있도록 해준다.


Loader(모듈) 불러오기

webpack은 모든 파일을 모듈로 바라보고 번들링 할 수 있다고 했지만, 기본적으로는 Javascript로 작성된 module, file만 읽을 수 있다. 또한, ES(ECMA) 버전에 따라 읽을 수 없는 JS 구문이 존재할 수도 있다. 다른 형식, 높은 버전의 JS의 파일도 읽어줄 수 있는 Loader를 불러와야한다. (Loader는 모듈이다.)

Loader를 불러오기 전에, 당연히 설치해야된다. npm install --save-dev babel-loader style-loader

module: {
    rules: [
	{ test: /.js$/, use: 'babel-loader' },
	{ test: /\.css$/, use: 'css-loader' },
        { test: /\.ts$/, use: 'ts-loader'}
    ]
},
  • module.rules 배열에 Loader를 추가해주면 된다.
  • Loader를 명시해 줄 때, 2가지의 property를 갖는 객체를 사용해야 한다.
    - test : 어떤 형식의 파일에 Loader를 사용할 것인지 명시
    - use : 어떤 Loader가 사용될지 명시

자주 사용하는 Loader

웹팩은 엔트리포인트부터 시작해서 모듈을 검색하다가, test에 규정한 파일 형식을 만나면, use에 지정한 loader로 처리한다.

[1] babel-loader

react를 사용하거나 ES6이상의 문법을 사용했다면, webpack으로 번들링 할 때, 트랜스파일링이 필요하다. 트랜스 파일링을 위해 babel-loader로 babel과 연동 할 수 있다.
npm i -D babel-loader

module : {
	rules : [
		{ test : /\.(js|jsx)$/, use : 'babel-loader' }
	]
},

[2] css-loader

웹팩은 모든 것을 모듈로 바라보기 때문에, js 파일 뿐만 아니라 스타일시트도 import 구문으로 불러올 수 있다. css-loader는 스타일시트를 js코드로 변경한다.
npm i -D css-loader

module : {
	rules : [
		{ test : /\.(js|jsx)$/, use : 'babel-loader' },
		{ test : /\.css$/, use : 'css-loader' }
	]
},

[3] style-loader

(css-loader로 스타일 시트를 모듈로 변경했다.) 모듈로 변경된 스타일시트는 돔에 추가되어야만 브라우저가 해석할 수 있다. css-loader는 스타일시트를 js코드로 변경했을 뿐, 돔에 추가해주지 않았다.

sytle-loader는 자바스크립트로 변경된 스타일을 돔에 추가하는 로더다. css를 번들링하기 위해서는 css-loader와 style-loader를 함께 사용해야 하며, css-loader를 사용한 후, style-loader를 적용해야 하므로, module에 기록하는 순서가 매우 중요하다.
npm i -D style-loader

module : {
	rules : [
		{ test : /\.(js|jsx)$/, use : 'babel-loader' },
		{ test : /\.css$/, use : ['style-loader','css-loader'] }
	]
},

css-loader가 먼저 적용되어야 하지만, use 배열에 기록할 때는 style-loader가 앞에 위치해야한다. use를 배열로 설정하면 뒤에서부터 앞으로 순서대로 로더가 동작하기 때문이다.
.css 확장자로 끝나는 모듈을 읽어들이면 css-loader를 적용한 후에 style-loader가 적용된다.


[4] file-loader

CSS 뿐만 아니라, 소스코드에서 사용하는 모든 파일을 모듈로 사용할 수 있다. 파일을 모듈 형태로 지원하고 웹팩 아웃풋에 파일을 옮겨주는 것이 file-loader가 하는 일이다.
가령 CSS에서 URL( )함수에 이미지 파일 경로를 지정할 수 있는데, 웹팩은 file-loader를 이용해서 이 파일을 처리한다.

style.css

body {
  background-image: url(bg.png);
}

배경 이미지를 bg.png 파일로 지정했다. 웹팩은 엔트리 포인트인 app.js가 로딩하는 style.css파일을 읽을 것이다. 그리고 이 스타일 시트는 url( )함수로 bg.png를 사용하는데, 이때 file-loader가 동작한다.
npm i -D file-loader

module : {
	rules : [
		{ test : /\.(js|jsx)$/, use : 'babel-loader' },
		{ test : /\.css$/, use : ['style-loader','css-loader'] },
		{ test : /\.png$/, use : 'file-loader' },
	]
},

웹팩이 .png 파일을 발견하면 file-loader를 실행한다. 로더가 동작하고 나면 아웃풋에 설정한 경로로 이미지 파일이 복사된다. 하지만 이대로 index.html 파일을 브라우저에 로딩하면 이미지를 제대로 로딩하지 못한다.
웹팩으로 빌드한 이미지 파일은 output에서 지정한 디렉토리 밑으로 이동한다. CSS를 로딩하면 background-image: url(bg.png) 코드에 의해, 동일 폴더에서 이미지를 찾으려고 시도하기 때문에 이미지 로딩에 실패한다.
따라서 이럴 땐 file-loader 옵션을 조정해서 경로를 바로 잡아야 한다.

module : {
	rules : [
		{ test : /\.(js|jsx)$/, use : 'babel-loader' },
		{ test : /\.css$/, use : ['style-loader','css-loader'] },
		{ test : /\.png$/, use : 'file-loader',options: {
           						  	publicPath : './dist/',
          							name : "[name].[ext]?[hash]"	
							}
		},
	]
},

publicPath 옵션은 file-loader가 처리하는 파일모듈로 사용할 때 경로 앞에 추가되는 문자열이다. output에 설정한 'dist'폴더에 이미지 파일을 옮길 것이므로, publicPath 값을 'dist'로 변경했다. 파일을 사용하는 쪽에서는 'bg.png'를 'dist/bg.png'로 변경하여 사용할 것이다.


[5] url-loader

사용하는 이미지 갯수가 많다면, 네트워크 리소스를 사용하는 부담이 있고 사이트 성능에 영향을 줄 수도 있다. 만약 한 페이지에서 작은 이미지를 여러개 사용한다면, Data URI Scheme를 이용하는 방법이 더 나은 경우도 있다. 이미지를 Base64로 인코딩하여 문자열 형태로 소스코드에 넣는 형식이다.

url-loader는 이러한 처리를 자동화해준다.
npm i -D url-loader

module : {
	rules : [
		{ test : /\.(js|jsx)$/, use : 'babel-loader' },
		{ test : /\.css$/, use : ['style-loader','css-loader'] },
		{ 
          	    test : /\.png$/, 
          	    use : 'file-loader', 
              	    options: {
                        publicPath : './dist/',
                        name : "[name].[ext]?[hash]"
                    }
        	},
		{
          	    test : /\.png$/,
          	    use : 'url-loader',
          	    options : {
                  	publicPath : './dist/',
                  	name : '[name].[ext]?[hash]',
                  	limit : 5000 //5kb 미만 파일만 data url로 처리
                    }
        	}
	]
},

limit 속성을 사용했다. 모듈로 사용한 파일중 크기가 5kb 미만인 파일만 url-loader를 적용하는 설정이다. 아이콘처럼 용량이 작거나 사용 빈도가 높은 이미지는 파일을 그대로 사용하기 보다는 Data URI Scheme을 적용하기 위해 url-loader를 사용하기 좋다.


[6] 커스텀 로더(모듈) 사용하기

웹팩이 불러오는 로더들은 모듈이다. 따라서 커스텀 모듈을 만들기 위해, module.exports를 사용

myloader.js

module.exports = function myloader(content){
	console.log("myloader is running")
	return content
}

webpack.config.js

모듈을 만들었으니, 웹팩이 로더로서 모듈을 불러올 수 있도록 해야한다.

module : {
	rules : [
		{test: /\.js$/, use : [path.join(__dirname, './myloader.js')] }
	]
}


5. Plugin

로더가 파일 단위로 처리하는 반면 플러그인은 번들된 결과물을 처리한다. 번들된 자바스크립트를 난독화 한다거나 특정 텍스트를 추출하는 용도로 사용한다.
webpack에서 bundling 되기 전이나 후에, 파일을 custom하여 개발자가 원하는 추가 기능을 넣을 수 있다. 이때 사용하는 것이 plugin 옵션이다.

HtmlWebpackPlugin

번들링 된 js 파일을 쓰려면 html에서 src로 불러와야한다.
webpack output인 dist에 index.html 파일을 놓는 방식이 있지만, dist는 배포 디렉토리이므로, dist 안에 index.html을 작성하는 것은 바람직하지 않다.
views 폴더에 index.html을 놓고 webpack 빌드시에 dist폴더로 index.html 과 bundle.js를 옮기는 방식으로 진행하는 것이 바람직하다.

이때 HtmlWebpackPlugin을 사용한다.
/views/index.html에 있는 파일을 output 경로에 옮겨주는 역할을 한다.

plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname,'./Views/index.html'),
      inject: true,
      filename: path.join(__dirname, './dist/index.html')
    }),
  ],

template 옵션 : view에 있는 index.html을 가리킨다.
filename 옵션 : output 경로.
inject 옵션 : 스크립트를 언제 불러줄지 정하는 옵션이다.

그렇다면, html을 번들링에 포함시키기 위해서 html-loader를 사용해야할까?
다시 알아보니, html-loader로도 가능한 것으로 보인다. 대신 이 플러그인이 더 많은 기능을 제공하는 것으로 보임

profile
한국외대 중국어&컴공 복수전공 - 세미 전공자의 기술 블로그

0개의 댓글