[JavaScript] Webpack, Babel, Polyfill

2023-09-18

  • Webpack은 여러개의 파일을 하나로 합쳐주는 모듈 번들러입니다.
  • 번들러를 사용하면 여러개 파일을 하나로 합쳐주기 때문에 네트워크 접속 부담을 줄여 더 빠른 서비스를 제공할 수 있습니다.
  • 트랜스파일링이란 특정 언어로 작성된 코드를 비슷한 다른 언어로 변환시키는 것입니다. 이를 해주는 것이 트랜스파일러입니다.

들어가기 전에


JavaScript는 원래 모듈을 지원하지 않았습니다. 하지만 개발자들의 노고 끝에 어떻게든 코드를 모듈화하고 서로 임포트하는 개념을 만들어 냈습니다. 이렇게 등장한 두 가지가 바로 CommonJs 모듈(node.js)과 Asynchronous Module Definition(Require JS)입니다.

아니 그렇다고 해도 모듈 개념이 없는 건 너무 하잖아요….하면서 JavaScript에 새로운 표준이 생겼습니다. 바로 ECMAScript6(ES6)입니다. ES6는 위의 두 가지의 특장점들을 가져와서 새로운 포맷을 만들어냈습니다.

  • CommonJS처럼 간결한 문법을 갖추어 싱글 export와 순환 의존성을 지원
  • AMD처럼 바로 비동기 로딩과 (설정가능한) 모듈 로딩을 지원

이것들과 더해 언어 자체가 모듈을 지원하며 장점도 추가되었습니다.

  • CommonJS보다 문법이 더 간결
  • 구조가 static하게 분석 가능하고, 최적화 가능
  • CommonJS보다 순환 의존성 지원이 잘됨

하지만 브러우저는 여전히 파일 단위 모듈을 잘 모릅니다.

ES6는 일부 브라우저에서만 지원합니다.(크롬, 사파리) 여러 버전의 각기 다른 브라우저는 이런 모듈화를 지원하지 않는 경우도 있습니다. 하나의 소스로 모든 브라우저에서 보여주는 것이 웹의 특장점입니다. 그래서 모듈을 하나의 파일로 묶어 네트워크 비용을 최소화 할 수 있어야 합니다. 이 과정을 번들링이라고 합니다. 그리고 이런 번들링해주는 툴을 번들러라고 합니다.

Webpack


Webpack은 여러개 파일을 하나로 합쳐주는 모듈 번들러입니다.

웹팩은 기본적으로 모듈을 지원하고 파일 분할 기능(원하는 코드만 따로 분리해서 하나의 파일로 압축 가능), CSS loader 기능, jsx 변환 작업도 해줍니다.

여러개로 나눠진 JavaScript 파일을 HTML이 실행할 수 있는 하나의 JavaScript 파일로 합쳐줍니다.

왜 웹팩을 사용할까요?

  • 파일이 여러개이면 많은 파일을 다운받아와야 하기 때문에 그만큼 네트워크 부하가 커지고 느려지고 같은 이름의 변수나 함수로 충돌 가능성이 있기 때문입니다.
  • 위와 같은 문제점들을 해결하기 위해 번들러라는 것이 등장하였습니다.
  • 번들러를 사용하면 여러개 파일을 하나로 묶어주기 때문에 네트워크 접속의 부담을 줄여 더 빠른 서비스를 제공할 수 있습니다.

Webpack의 4가지 개념


엔트리(entry)

엔트리는 의존성 그래프의 시작점을 의미합니다. 엔트리 파일을 의존하는 파일은 없고, 엔트리가 A를 의존하고, A가 다시 B, C를 의존하는 식으로 모듈이 연결됩니다. 이때 웹팩은 이미지, 폰트, 스타일시트 역시 모듈로 관리합니다. 설정 파일에서 엔트리 파일을 지정할 수 있습니다.

module.exports = {
	entry: {
		main: './src/main.js',
	}
}

이렇게 넣으면 시작점이 src/main.js가 됩니다. entry 키에 시작점 경로를 지정합니다.

아웃풋(output)

엔트리에 설정한 JavaScript 파일을 시작으로, 의존되어 있는 모듈을 하나로 묶어서 내보냅니다.(번들링) 번들된 결과물이 나오는 위치는 output 키에 기록합니다.

module.export = {
	output: {
		filename: 'bundle.js',
		path: 'dist',
	}
}

dist 폴더에 bundle.js 파일에 결과가 나오게 됩니다.

html 파일에는 번들링된 이 파일만 나오게 되면 됩니다.

<body>
	<script src="./dist/bundle.js"></script>
</body>

웹팩은 터미널에서 webpack 커맨드를 입력하여 바로 빌드할 수 있습니다. webpack이 기본적으로 내장되어 있지 않은 경우 node.js 설치 후 npm install -g webpack으로 전역 설치를 해주면 됩니다.

로더(loader)

웹팩은 JavaScript 파일 뿐만 아니라 이미지, 폰트, 스타일시트까지 전부 모듈로 관리합니다. 어떻게 관리하는 것일까요? 웹팩은 기본적으로 JavaScript 밖에 모릅니다. JavaScript가 아닌 파일들은 웹팩이 이해하도록 변경해야 합니다. 이 역할을 바로 로더가 해주게 됩니다.

CSS-loader

CSS를 JavaScript 파일로 변환해서 로딩할 때 사용하는 로더입니다.

moudle.exports = {
	module: {
		rules: [{
			test: /\.css$/,
			use: ['style-loader', 'css-loader']
		}]
	}
}

플러그인(plugin)

로더는 번들링이 되기 전의 파일 단위를 처리하는 반면, 플러그인은 번들된 결과물을 추가로 처리합니다. 번들된 JavaScript를 난독화를 시킨다거나 특정 텍스트를 추출하는 용도로 사용할 수 있습니다.

Babel


트랜스파일링이란 특정 언어로 작성된 코드를 비슷한 다른 언어로 변환시키는 것입니다. 이를 해주는 것이 트랜스파일러입니다.

대표적인 트랜스파일러로는 Babel이 있습니다.

모든 브라우저가 최신 문법을 이해하지 못하기 때문에 ES5로 바꿔주는 과정이 필요합니다. 이 과정을 해주는 JavaScript 트랜스파일러가 바벨입니다. 이로써 개발자는 ES6+ 버전으로 개발할 수 있으니 생산성은 향상됩니다.

다만 babel을 사용한다고 해서 모든 최신 JavaScript 문법을 다 사용할 수 있는 것은 아닙니다. 그래서 브라우저 자체에서 지원하지 않는 함수를 검사하는 작업이 프로그램 시작에 진행되어야 합니다. 이 역할은 babel-polyfill이 담당합니다.

트랜스파일링이 왜 필요할까요?

  • 모든 브라우저가 ES6를 제공하지 않기 때문에 ES5로 변환시키는 과정이 필요하기 때문입니다.

Webpack 사용 예시


적용하고자 하는 폴더에 webpack과 webpack-cli를 설치해줍니다.

npm init
npm i react react-dom
npm i -D webpack webpack-cli

다음으로 바벨을 설치해줍니다.

npm i -D @babel/core @babel/preset-env @babel/preset-react babel-loader

babel-loader는 바벨과 웹팩을 연결해주는 역할을 합니다.

preset-env는 자동으로 옛날 브라우저들을 지원해줍니다.

WordRelay.jsx 파일

const React = require('react'); // npm에서 react 불러오기
const { Component } = React;
 
class WordRelay extends Component {
	state = {
		text: 'Hello, Webpack',
	};
	render() {
		return <h1>{this.state.text}</h1>
	}
}
 
module.exports = WordRelay; // 쪼갠 컴포넌트를 외부에서도 사용 가능하도록 만들어줌

client.jsx 파일

const React = require('react');
const ReactDom = require('react-dom');
 
// 필요한 것만 가져와
const WordRelay = require('./WordRelay');
 
ReactDom.render(<WordRelay />, document.querySelector('#root'));

client.jsx 파일에 WordRelay.jsx 파일을 합쳐줍니다.

webpack.config.js

const path = require('path');
 
module.exports = {
	name: 'wordrelay-setting',
	mode: 'development', // 실 서비스에서는 production
	devtool: 'eval', // production일 때에는 hidden-source-map 사용
	resolve: {
		extensions: ['.js', '.jsx'] // js나 jsx 파일 확장자가 있는지 찾음
	},
	entry: {
		app: ['./client'],
	}, // 입력
	
	module: {
		rules: [{
			test: /\.jsx?/,
			loader: 'babel-loader',
			// js나 jsx 파일에 바벨로더를 적용해 최신문법이 옛날 브라우저에서도 돌아갈 수 있도록 해줌
			options: {
				presets: ['@babel/preset-env', '@babel/preset-react'],
			},
		}],
	},
	
	output: {
		path: path.join(__dirname, 'dist'),
		filename: 'app.js',
	}, // 출력
}

결과적으로 여러개의 파일을 합쳐 현재 폴더 내에 dist 폴더가 생기고 그 안에 app.js라는 하나의 파일이 생성됩니다.

Webpack 속성 종류


  • mode: 모드에 따라 번들링 최적화를 진행합니다. (development/production)
  • entry: 웹팩에서 웹 자원을 변환하는 데 필요한 진입점이자 JavaScript 파일 경로이고 번들링 시작점입니다.
  • module: 웹팩에서 사용하는 모듈에 대한 설정/웹팩 로더 설정입니다. rules로 loader를 설정합니다.
  • ouput: 웹팩을 돌리고 난 결과불의 파일 경로입니다. 번들링 결과물 경로 및 이름을 지정합니다.
  • plugins: 기본적인 동작에 추가적인 기능을 제공합니다. 확장 프로그램 같은 것입니다.
  • target: 웹팩에서 번들링 결과를 어떤 목표로 하는지 설정합니다. (web, webworker, es5, es2020, node)
  • devtool: 소스맵 생성 관련 설정입니다. (source-map, inline-source-map 등)

전체적인 과정은 entry에 있는 파일에 module을 적용하고 추가적으로 plugins를 사용해 output으로 출력하는 것입니다.

Polyfill


브라우저에서 지원하지 않는 코드를 사용 가능한 조각이나 플러그인(추가기능)을 의미합니다.

Babel만 있으면 되는 거 아닙니까?

  • 바벨은 ESNext에서 지원하는 문법을 ES5로 번역해주지만, ES5에 존재하지 않는 ES6의 Map, Promise, Set, Object.assigin() 이런 애들은 존재하지 않으니 번역을 해줄 수가 없습니다.
  • 그래서 이것을 보완하기 위해 polyfill을 사용합니다. (Map, Promise, Set 등을 사용가능한 객체로 만들어줍니다.)
  • babel은 babel-polyfill 모듈을 사용하면 되지만, 현재 deprecated 되었기 때문에 core-js와 regenerator-runtime을 직접 사용하는 방식을 제안하고 있습니다.

Reference

https://juneyr.dev/2019-02-20/webpack-babel https://velog.io/@dbsbest10/Webpack-과-Babel이란-무엇일까

예상 질문

  • Webpack은 무엇입니까?
  • Webpack을 사용하는 이유는 무엇입니까?
  • Babel은 무엇입니까?
  • Babel을 사용하는 이유는 무엇입니까?
javascriptwebpackbabelPolyfill

프로필 사진
TaeWoo Kim
Junior Frontend Engineer