[프론트엔드 개발 툴] 웹팩 기본

이윤우·2023년 3월 31일
0

Webpack

목록 보기
1/1
post-thumbnail

0. 실습 환경

npm install -D webpack@4
npm install -D webpack-cli@3
npm install -D css-loader@3
npm install -D file-loader@5
npm install -D style-loader@1
npm install -D url-loader@3
npm install -D html-webpack-plugin@3
npm install -D mini-css-extract-plugin@0
npm install -D optimize-css-assets-webpack-plugin@5

1. Webpack의 역할

웹팩은 오픈소스 자바스크립트 모듈 번들러로 ECMAScript2015 모듈시스템을 쉽게 사용하도록 돕는 역할을 한다.

모듈 번들러
웹 애플리케이션을 구성하는 자원(HTML, CSS, JavaScript, Images 등)을 모두 각각의 모듈로 보고 이를 조합해서 병합된 결과물을 만드는 도구를 의미한다.

2. 엔트리와 아웃풋

하나의 시작점으로부터 의존적인 모듈을 전부 찾아내서 하나의 결과물을 만들어 낸다.

  • --mode: 웹팩 실행 모드
  • --entry: 시작점 경로
  • --output: 번들링 결과물 경로

webpack.config.js

const path = require('path');

module.exports = {
	mode: 'development',
  	entry: {
    	main: './src/app.js',
    },
  	output: {
    	path: path.resolve('./dist'),
      	filename: '[name].js',
    },
};

package.json

{
	'script': {
    	'build': './node_modules/.bin/webpack'
    }
}

번들링 실행

$ npm run build

this[kHandle] = new _Hash(algorithm, xofLen); 에러 해결 방법

$ export NODE_OPTIONS=--openssl-lagacy-provider

3. 로더

로더는 타입스크립트 같은 다른 언어를 자바스크립트 문법으로 변환해 주거나 이미지를 data URL 형식의 문자열로 반환해줍니다. 뿐만 아니라 CSS 파일을 자바스크립트에서 직접 로딩할 수 있도록 해줍니다.

1) CSS 변환 (css-loader, style-loader)

css-loader를 이용해서 CSS 파일을 모듈처럼 볼러와 사용하고 style-loader를 통해 모듈로 변경된 스타일 시트를 돔에 추가합니다.

// webpack.config.js
module.exports = {
	module: {
    	rules: [{
        	test: /\.css$/,
          	use: ['style-loader', 'css-loader'], // style-loader를 앞에 추가!!
        }]
    }
}

배열을 설정하면 뒤에서부터 앞의 순서대로 로더가 동작하기 때문에 css-loader, style-loader 순으로 적용할 수 있도록 설정합니다.

2) 소스코드에서 사용하는 모든 파일(file-loader)

file-loader를 통해 소스코드에서 사용하는 모든 파일을 모듈로 사용하게끔 할 수 있습니다.

// webpack.config.js
module.exports = {
	module: {
    	rules: [
          	{
              	test: /\.(png|jpg)/,
              	loader: 'file-loader',
              	options: {
                	publicPath: './dist/', // prefix를 아웃풋 경로로 지정
                  	name: '[name].[ext]?[hash]', // 파일명 형식
                }
          	}
        ]
    }
}
  • publicPath: file-loader가 처리하는 파일을 모듈로 사용할 때 경로 앞에 추가되는 문자열입니다.
  • name: 로더가 파일을 아웃풋에 복사할 때 사용하는 파일 이름입니다.

3) 작은 이미지를 여러 개 사용하는 경우 (url-loader)

url-loaderData URL Scheme을 이용할 수 있도록 이미지를 Base64로 인코딩하여 문자열 형태로 소스코드에 넣어줍니다.

Data URL Scheme
data:스킴이 접두어로 붙은 URL로 작은 파일을 문서 내에 인라인으로 임베드하기 위한 URL 스킴입니다. 주로 아이콘 등의 작은 이미지 파일에 사용됩니다.

// webpack.config.js
module.exports = {
	module: {
    	rules: [
          	{
            	test: \/.png$\,
              	use: {
            		loader: 'url-loader',
              		options: {
            			publicPath: './dist/',
              			name: '[name].[ext]?[hash]',
              			limit: 5000 // 5kb 미만 파일만 data url로 처리
            		}
            	}
            }
        ]
    }
}

4. 플러그인

로더가 파일 단위로 처리하는 반면 플러그인은 번들된 결과물을 처리합니다. 번들된 자바스크립트를 난독화 한다거나 특정 텍스트를 추출하는 용도로 사용합니다.

1) 결과물에 빌드 정보나 커밋 버전등을 추가 (BannerPlugin)

BannerPlugin을 통해 번들된 결과물에 빌드 정보나 커밋 버전같은 걸 추가할 수 있습니다. 배너 정보가 많다면 별도 파일로 분리하는 것을 권장합니다.

// banner.js
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}\n Build Date: ${data}\n Author: ${user}`
    )
}

// webpack.config.js
const webpack = require('webpack')
const banner = require('./banner.js')

module.exports = {
	plugins: [
    	new webpack.BannerPlugin(banner)
    ]
}

2) 환경 정보 제공 (DefinePlugi)

애플리케이션은 개발환경과 운영환경으로 나눠서 운영합니다. 환경에 따라 API 서버 주소가 다를 수 있습니다. 같은 소스 코드를 두 환경에 배포하기 위해서는 이러한 환경 의존적인 정보를 소스가 아닌 곳에서 관리하는 것이 좋습니다. 웹팩은 이러한 환경 정보를 제공하기 위해 DefinePlugin을 제공합니다.

// webpack.config.js

const webpack = require('webpack')

export default {
	plugins: [new webpack.DefinePlugin({
    	VERSION: JSON.stringify('v.1.2.3'),
      	PRODUCTION: JSON.stringify(false),
      	MAX_COUNT: JSON.stringify(999),
      	'api.domain': JSON.stringify('http://dev.api.domain.com'),
    })],
}

3) HTML 파일 후처리 (HtmlWebpackPlugin)

HtmlWebpackPlugin은 HTML 파일을 후처리하는데 사용합니다. 빌드 타임의 값을 넣거나 코드를 압축할 수 있습니다.

<!DOCTYPE html>
<html>
  <head>
    <title>타이틀<%= env %></title>
  </head>
  <body>
  </body>
</html>

타이틀 부분에 ejs 문법을 이용해서 env 변수 값을 출력하려고 합니다. HtmlWebpackPlugin은 이 변수에 데이터를 주입시켜 동적으로 HTML 코드를 생성합니다.

// webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports {
	plugins: [
    	new HtmlWebpackPlugin({
        	template: './src/index.html', // 템플릿 경로 지정
          	templateParameters: { // 템플릿에 주입할 파라미터 변수 지정
            	env: prosecc.env.NODE_ENV === 'development' ? '(개발용)': '',
            },
          	minify: process.env.NODE_ENV === 'production' ? {
            	collapseWhitespace: true, // 빈칸 제거
              	removeComments: true, // 주석 제거
            } : false,
        })
    ]
}

4) 빌드 이전 결과물 제거 (CleanWebpackPlugin)

CleanWebpackPlugin을 통해 빌드 이전 결과물을 제거할 수 있습니다.

// webpack.config.js

const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
	plugins: [new CleanWebpackPlugin()],
}

5) CSS를 별도의 파일로 뽑아냄 (MiniCssExtractPlugin)

스타일시트가 점점 많아지면 하나의 자바스크립트 결과물로 만드는 것이 부담일 수 있다. 번들 결과에서 스타일시트 코드만 뽑아서 별도의 CSS 파일로 만들어 역할에 따라 파일을 분리하는 것이 좋다. 브라우저에서 큰 파일 하나를 내려받는 것보다 여러 개의 작은 파일을 동시에 다운로드하는 것이 빠르다.

// webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
	plugins: [
    	...(process.env.NODE_ENV === 'production'
            ? [new MiniCssExtractPlugin({ filename: `[name].css]`})
            : []),
    ]
}

0개의 댓글