꼬꼬마 블로그

꼬꼬마의 기술 블로그

자바스크립트 번들러, esbuild로 React 빌드하기

새로운 자바스크립트 번들러 esbuild를 알아보고 React 빌드하기

#esbuild#React
2022.04.21.

자바스크립트에서 모듈이 등장하고 이런 모듈을 번들링하기 위한 번들러가 등장했다.

현재까지도 가장 많이 사용하는 webpack이 대표적인 번들러다.

회사에서도 webpack을 통해 번들링하고 있는데 프로젝트가 커서 빌드가 꽤 오래 걸린다.

그래서 알아보던 중 빠른 새로운 번들러를 알게됐고 그게 esbuild다.

esbuild

esbuild에서 제공하는 다른 번들러와의 속도 차이이다. 꽤 많은 차이가 난다.

esbuild 속도 차이

esbuild가 이렇게 빠를 수 있는 이유를 esbuild에서는 아래와 같이 설명한다. (자세한 내용은 공식문서 참고)

  • Go로 작성됨
  • 병렬 처리
  • 효율적인 메모리 사용
  • esbuild는 처음부터 모두 직접 개발함

esbuild는 컨텐츠 타입에 맞는 loader를 가지며 loader를 통해 파일을 esbuild가 읽을 수 있게 한다.

기본으로 내장된 loader가 있고 js, jsx, ts, tsx loader가 지원된다.

기본으로 내장된 컨텐츠 타입과 loader은 공식문서에 정리되어있다.

esbuild + react

esbuildreact를 실행하며 사용법을 간단히 익혀보자

React 18 기준으로 작성되어 ReactDOM.render가 사용되지 않는다.

esbuildreact관련된 패캐지를 설치한다.

$ mkdir {project}
$ cd {project}
$ yarn init
$ yarn add -D esbuild
$ yarn add react react-dom

이후 index.jsx, App.jsx, util.js 파일을 작성했다.

// src/index.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);
// src/App.jsx
import React from 'react';
import { getRandomWelcomeText } from './utils';
function App() {
return (
<div>
<h1>{getRandomWelcomeText()}</h1>
</div>
);
}
export default App;
// src/utils.js
export function getRandomWelcomeText() {
const welcomeTexts = ['Hello World', 'Welcome', 'Hi esbuild'];
return welcomeTexts[Math.ceil(Math.random() * 10) % welcomeTexts.length];
}

그리고 yarn build 명령어를 추가하자

// package.json
...
"scripts": {
"build": "esbuild src/index.jsx --outdir=dist --bundle"
}
...

outdir은 번들링 된 파일을 위치할 폴더이고 --bundle 옵션을 통해서 import된 파일을 모두 하나의 파일로 번들링한다.

마지막으로 html 파일을 만들어주면 된다.

<!-- index.html -->
<!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>
<script src="./dist/index.js" defer async></script>
<body>
<div id="root"></div>
</body>
</html>

빌드 후 index.html 파일 브라우저에서 확인해보면 잘 동작하는걸 확인할 수 있다.

$ yarn build

실행 결과

간단히 esbuild + react로 앱을 실행해봤다.

아직 일반 번들러와 직접 비교해보지 못했지만 확실히 빠르다는 느낌이 있었다.

webpack vs esbuild

webpack으로 번들링한 결과와 esbuild로 번들링한 결과를 비교해봤다.

먼저 기존에 가장 많이 쓰는 webpack + babel 조합으로 빌드해봤다.

const path = require('path');
module.exports = {
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
},
module: {
rules: [
{
test: /\.(jsx|ts)$/,
use: {
loader: 'babel-loader',
options: {
loader: 'jsx',
},
},
},
],
},
};

간단히 babel-loader만 사용하도록 webpack 설정을 한 후 번들링한 결과다.

webpack 번들링 결과

별다른 설정이 없을때 3.18s가 걸렸다.

다음으로 esbuild (+ esbuild-loader) esbuild 번들링과 내부 loader를 사용한 결과다.

esbuild 번들링 결과

0.37s가 걸렸다. 생각보다 차이가 많이 난다.

지금은 페이지 하나에 해당하는 코드를 번들링한 결과 차이다.

하지만 실제로 사이드 프로젝트에 적용했을때도 생각보다 차이가 많이 났다.

babel-loader vs esbuild-loader

이렇게만 보면 babel이 느린건지 webpack이 느린건지 알 수 없다.

webpack + esbuild-loader의 조합도 확인해봤다.

webpack + esbuild-loader 결과

3.40s초로 babel-loader를 사용했을때 보다 크게 차이가 나지 않았다.

코드 양이 작아서 크게 체감되지 않았을 수 있다.

그래서 실제 사이드프로젝트에 webpack + esbuildwebpack + babel을 사용해 확인해봤을때 평균 4.0s정도 webpack + esbuild가 빨랐다


esbuild를 사용해보니 생각보다 기존 도구들과 차이가 나서 다음에 실제로 적용해보고 싶다.

다음에 적용하게 된다면 추가로 글을 남겨야겠다.