Devahoy Logo
PublishedAt

ESBuild

ลองหัดใช้งาน esbuild เบื้องต้น

ลองหัดใช้งาน esbuild เบื้องต้น

วันนี้ผมได้ลองใช้งาน esbuild ครั้งแรก ซึ่งก่อนหน้านี้ เคยได้ยิน และได้เห็นผ่านตา แต่ไม่เคยได้จับมันจริงๆ เพราะส่วนใหญ่ผมก็จะเป็นแค่ผู้ใช้งาน Library/ Frmework เลยไม่ได้ลงไปถึงขั้นต้อง config webpack/esbuild อะไรพวกนั้น

หลังจากได้ลองเล่นไปนิดๆหน่อย ก็ลองมาเขียนบทความบันทึกไว้ครับ ซึ่งส่วนใหญ่ Reference ผมก็อ่านจาก Official esbuild ครับ

esbuild คืออะไร?

esbuild เป็น JavaScript bundler/Compiler ที่เขียนด้วยภาษา Go คล้ายๆกับ Webpack, Rollup หรือ SWC คือทำหน้าที่ รวมไฟล์ แปลงไฟล์ minify ต่างๆ

Feature หลักๆ คือ

  • ES6 และ CommonJS
  • รองรับ Tree shaking (คือ module ไหนไม่ได้ import ก็ไม่ถูกยัดรวม bundle)
  • มี API สำหรับ JavaScript และ Go
  • รองรับ TypeScript และ JSX
  • Sourcmap และ Minify เป็นต้น

Install esbuild

เริ่มต้น เราจะทำการสร้างโปรเจ็คขึ้นมาก่อน ผมตั้งชื่อให้มันว่า try-esbuild ละกัน และก็ initial project ด้วย yarn

Terminal window
mkdir try-esbuild
cd try-esbuild
yarn init -y

จากนั้นทำการ install esbuild ลงไป

Terminal window
yarn add esbuild

ตัว esbuild เราก็จะสามารถเรียกจาก folder นี้ได้แล้ว:

Terminal window
./node_modules/.bin/esbuild --version
0.14.36

First bundle

ต่อมาลอง build จริงๆ ด้วยการใช้ React และ ReactDOM กัน ทำการติดตั้ง dependencies:

Terminal window
yarn add react react-dom

ต่อมาสร้างไฟล์ app.jsx ขึ้นมา มีโค๊ดดังนี้

app.jsx
1
import * as React from 'react'
2
import * as Server from 'react-dom/server'
3
4
let Greet = () => <h1>Hello, world!</h1>
5
console.log(Server.renderToString(<Greet />))

ตัวโค๊ดด้านบน ใช้ความสามารถของ react เพื่อ server render ทำให้เราสามารถรันด้วยคำสั่ง node ได้

ซึ่งถ้าเรารันตรงๆ แบบนี้ จะ error:

Terminal window
node app.jsx

ต้องทำการ bundle file ด้วย esbuild ก่อน แบบนี้:

Terminal window
./node_modules/.bin/esbuild app.jsx --bundle --outfile=out.js

จะได้ไฟล์ผลลัพธ์และไฟล์ output คือ out.js

Terminal window
out.js 507.3kb
Done in 10ms

เมื่อได้ไฟล์นี้เราสามารถรันด้วยคำสั่ง

Terminal window
node out.js
<h1>Hello, world!</h1>

React App

เผื่อยังไม่เห็นภาพ ลองเป็น React ฝั่ง Client บ้าง ผมสร้างโฟลเดอร์มาใหม่ ขื่อ src ข้างในมีไฟล์ App.jsx ดังนี้ (เอามาจาก template ของ create-react-app)

App.jsx
1
import React from 'react'
2
3
function App() {
4
return (
5
<div className="App">
6
<header className="App-header">
7
<h1>üëã Hello esbuild!</h1>
8
</header>
9
</div>
10
)
11
}
12
13
export default App

และไฟล์ src/index.jsx เป็นแบบนี้

src/index.jsx
1
import React from 'react'
2
import ReactDOM from 'react-dom/client'
3
4
import App from './App'
5
6
const root = ReactDOM.createRoot(document.getElementById('root'))
7
root.render(
8
<React.StrictMode>
9
<App />
10
</React.StrictMode>
11
)

ต่อมา ก็ทำการ bundle ไฟล์ ไว้ที่โฟลเดอร์ dist (ใช้ --outdir แทน --outfile ก่อนหน้านี้)

Terminal window
./node_modules/.bin/esbuild --bundle src/index.jsx src/App.jsx --outdir=dist

สร้างไฟล์ index.html ขึ้นมา

index.html
1
<!doctype html>
2
<html lang="en">
3
<head>
4
<meta charset="utf-8" />
5
<meta name="viewport" content="width=device-width, initial-scale=1" />
6
<meta name="description" content="Hello esbuild" />
7
<title>Hello esbuild</title>
8
</head>
9
<body>
10
<noscript>You need to enable JavaScript to run this app.</noscript>
11
<div id="root"></div>
12
13
<script src="dist/index.js"></script>
14
</body>
15
</html>

ทดลองเปิด Local server

Terminal window
python3 -m http.server

หรือใช้ Serve

Terminal window
npx serve

จะเห็นข้อความว่า 👋 Hello esbuild!

Build scripts

จะดีกว่ามั้ย ถ้าเราเปลี่ยนคำสั่งไปใช้ package scripts แทน ที่จะต้องมาพิมพ์บ่อยๆ? เพิ่มลงไปใน package.json

package.json
1
{
2
"scripts": {
3
"build": "esbuild --bundle src/index.jsx src/App.jsx --outdir=dist"
4
}
5
}

เวลาใช้งาน ก็แค่:

Terminal window
yarn build

นอกจาก Command line แล้ว เราสามารถใช้ JavaScript API ได้ เหมือนกัน เช่น ผมตั้งชื่อว่า build.js

build.js
1
require('esbuild')
2
.build({
3
logLevel: 'info',
4
entryPoints: ['src/App.jsx', 'src/index.jsx'],
5
bundle: true,
6
outdir: 'dist'
7
})
8
.catch(() => process.exit(1))

เวลาใช้งานก็ใช้ node เพื่อรัน bundle

Terminal window
node build.js

จะได้ผลลัพธ์เท่ากับแบบ command line

Build browser

ก่อนหน้านี้เรา build แต่ว่ายังไม่ได้ minify ให้มันเลย ไฟล์ใหญ่มาก เราสามารถ minify, sourcemap ให้มัน หรือจะกำหนด browser support ให้มันก็ได้ เช่น

Terminal window
esbuild app.jsx --bundle --minify --sourcemap --target=chrome58,firefox57

ทดลองเพิ่ม minify และสังเกตขนาดไฟล์ดูครับ

นอกจากนี้เราก็สามารถ bundle ไฟล์ css ได้เช่นกันครับ คำสั่งก็เหมือนกัน

Terminal window
esbuild --bundle app.css --outfile=out.css

Analyze

เราสามารถใช้ --analyze เพื่อดูรายละเอียดไฟล์ได้ด้วย

Terminal window
esbuild --bundle src/index.jsx src/App.jsx --minify --analyze --outdir=dist

จะได้ผลลัพธ์ประมาณนี้

Terminal window
dist/index.js 138.8kb
dist/App.js 7.3kb
dist/index.js 138.8kb 100.0%
node_modules/react-dom/cjs/react-dom.production.min.js 126.5kb 91.1%
node_modules/react/cjs/react.production.min.js 6.4kb 4.6%
node_modules/scheduler/cjs/scheduler.production.min.js 3.9kb 2.8%
node_modules/react-dom/index.js 253b 0.2%
src/App.jsx 220b 0.2%
src/index.jsx 188b 0.1%
node_modules/react-dom/client.js 107b 0.1%
node_modules/react/index.js 51b 0.0%
node_modules/scheduler/index.js 51b 0.0%
dist/App.js 7.3kb 100.0%
node_modules/react/cjs/react.production.min.js 6.3kb 86.2%
src/App.jsx 214b 2.9%
node_modules/react/index.js 46b 0.6%
Done in 0.26s.

สรุป

วันนี้ก็ลองเล่น esbuild ไปแบบเบื้องต้น ก็ทำให้มองเห็นภาพการทำงานมากขึ้น สิ่งที่น่าสนใจและน่าลองศึกษาต่อคือการ bundle รวมไฟล์ แยกไฟล์ แยกโฟลเดอร์ อะไรพวกนั้น แล้วก็การ generate hash ให้ไฟล์ การทำหรือใช้ plugin ต่างๆ รวมถึงพวก watch / hot reload และ WASM

Happy Coding ❤️

Reference

Authors
avatar

Chai Phonbopit

เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust