- Bun 1.2 เป็นรีลีสใหญ่ที่มุ่งเป็นเครื่องมือพัฒนา JavaScript/TypeScript แบบ full-stack โดยขยายทั้ง ความเข้ากันได้กับ Node.js รวมถึง runtime, bundler, test runner และ package manager ไปพร้อมกัน
- เสริมการตรวจสอบความเข้ากันได้ด้วยการรันชุดทดสอบของ Node.js ทุกครั้งที่มีการเปลี่ยนแปลง และเพิ่มการรองรับ
node:http2,node:dgram,node:cluster,node:zlib,node:v8 - API ในตัวใหม่
Bun.s3และBun.sqlดึงการเข้าถึง object storage ที่เข้ากันได้กับ S3 และ Postgres เข้ามาไว้ใน runtime เพื่อลดการพึ่งพา client ภายนอก - package manager เปลี่ยน lockfile เริ่มต้นจากไบนารี
bun.lockbเป็นbun.lockแบบ JSONC และเพิ่ม.npmrc,bun publish,bun patch,bun outdated,bun run --filter - มีการเปลี่ยนแปลง working directory ของ
bun run, การจัดการความล้มเหลวของBun.build(), ค่าที่server.stop()ส่งกลับ,bun -pและค่าเริ่มต้นของ sourcemap ดังนั้นโปรเจกต์เดิมควรตรวจสอบ ผลกระทบต่อการย้ายเวอร์ชัน
เสริมความเข้ากันได้กับ Node.js
- Bun 1.2 เปลี่ยนกระบวนการปรับปรุงความเข้ากันได้ โดยรัน ชุดทดสอบของ Node.js ทุกครั้งที่มีการเปลี่ยนแปลงใน Bun
- ก่อนหน้านี้การแก้บั๊กเน้นอิงจาก GitHub issue หรือรายงานว่าแพ็กเกจ npm รันล้มเหลว แต่แนวทางนี้ใกล้เคียงกับการ “ไล่ตีตัวตุ่น” ซึ่งทำให้การรีแฟกเตอร์ครั้งใหญ่ทำได้ยาก
- ได้พอร์ตไฟล์ทดสอบหลายพันไฟล์จาก repository ของ Node.js มาใช้กับ Bun และรันทดสอบเหล่านี้ทุก commit เพื่อตรวจสอบความเข้ากันได้
- การทดสอบของ Node.js บางกรณีตรวจสอบรายละเอียดการทำงานภายในและข้อความ error ที่ตรงกันเป๊ะ ๆ ดังนั้นในบาง test Bun จึงเปลี่ยน internal binding เป็น stub ของตนเอง หรือปรับให้ตรวจสอบโดยเน้น
nameและcode- Bun พยายามทำให้ข้อความ error ตรงกับ Node.js ให้มากที่สุด แต่หาก
nameและcodeเหมือนกัน ก็อาจให้ข้อความที่เป็นประโยชน์กว่าได้ในบางกรณี
- Bun พยายามทำให้ข้อความ error ตรงกับ Node.js ให้มากที่สุด แต่หาก
- โมดูลและฟีเจอร์ของ Node.js ที่รองรับใหม่
node:http2: รองรับการสร้างเซิร์ฟเวอร์ HTTP/2 และจำเป็นสำหรับเซิร์ฟเวอร์ gRPC ด้วยnode:dgram: รองรับ bind/connect ของ UDP socketnode:cluster: สามารถรัน Bun หลาย instance เพื่อกระจายงานไปยัง CPU หลายคอร์node:zlib: เขียน implementation จาก JavaScript ใหม่เป็น native code และเร็วกว่า Bun 1.1 ถึง 2 เท่าnode:v8: ใช้getHeapSnapshot,writeHeapSnapshotเพื่อตรวจสอบ heap ของ Bun ใน Chrome DevTools ได้
- เซิร์ฟเวอร์
node:http2ใน Bun 1.2 เร็วกว่า 2 เท่า เมื่อเทียบกับ Node.js expressประมวลผล HTTP request ได้เร็วกว่า Node.js สูงสุด 3 เท่า จากการปรับปรุงความเข้ากันได้ของnode:httpและการปรับแต่งเซิร์ฟเวอร์ HTTP ของ Bun- เพิ่มการรองรับ C++ addon ที่ใช้ V8 C++ API ด้วย
- Node.js ใช้ V8 ส่วน Bun ใช้ JavaScriptCore ทำให้การ implement มีความยากสูง
- Bun implement public C++ API ของ V8 บน JavaScriptCore เพื่อให้แพ็กเกจอย่าง
cpu-featuresทำงานได้ - การรองรับ V8 C++ API มีความซับซ้อน จึงอาจยังมีฟีเจอร์ที่ขาดอยู่ในแพ็กเกจส่วนใหญ่ และยังคงปรับปรุงการรองรับแพ็กเกจอย่าง
node-canvas@v2และnode-sqlite3ต่อไป
S3 API ในตัว Bun.s3
- Bun 1.2 เพิ่ม
Bun.s3ซึ่งเป็น API ในตัว สำหรับจัดการ object storage ที่เข้ากันได้กับ S3- ใช้ได้กับบริการที่ implement S3 API เช่น Amazon S3, Google Cloud Storage, Cloudflare R2
- จัดการการอ่าน เขียน และลบไฟล์ด้วย API ที่เข้ากันได้กับ Web standard
Blob
s3.file()ส่งคืน lazy reference ไปยังไฟล์ S3 และใช้งานได้แบบเดียวกับ BunFileAPI เช่นtext(),json(),arrayBuffer(),stream()- S3 client ของ Bun เขียนด้วย native code ไม่ใช่ JavaScript
- เมื่อเทียบกับการใช้
@aws-sdk/client-s3บน Node.js การดาวน์โหลดไฟล์จาก S3 bucket เร็วกว่า 5 เท่า
- เมื่อเทียบกับการใช้
- ฟีเจอร์เขียนข้อมูลมี
write()และwriter()write()อัปโหลด string,Uint8Array,Blob,Responseฯลฯ ได้writer()ทำ multipart upload สำหรับไฟล์ขนาดใหญ่
presign()สร้าง presigned URL ที่อนุญาตให้อัปโหลดไฟล์เฉพาะรายการได้- ทำให้ผู้ใช้อัปโหลดไปยัง S3 ได้โดยตรงโดยไม่เปิดเผย credential หรือให้สิทธิ์เข้าถึง bucket เกินจำเป็น
- เมื่อใช้ร่วมกับ
Bun.serve()การใช้new Response(s3.file(...))จะ redirect ไปยัง presigned URL แทนที่เซิร์ฟเวอร์จะดาวน์โหลดไฟล์จาก S3 แล้วส่งต่ออีกครั้ง- ลดการใช้หน่วยความจำ เวลา และค่า bandwidth ที่เซิร์ฟเวอร์ต้องใช้ในการดาวน์โหลดไฟล์
- URL แบบ
s3://ใช้ได้กับBun.file()และfetch()ด้วย- อัปโหลด ดาวน์โหลด และลบได้ด้วย
fetch("s3://...") S3Clientเริ่มต้นตั้งค่าผ่าน environment variables เช่นAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY
- อัปโหลด ดาวน์โหลด และลบได้ด้วย
Postgres client ในตัว Bun.sql
- Bun 1.2 เพิ่ม
Bun.sqlซึ่งเป็น SQL client ในตัวที่รองรับ Postgres- ก่อนหน้านี้ Bun มี SQLite client ในตัวอยู่แล้ว และรีลีสนี้ขยายขอบเขตการรองรับฐานข้อมูล SQL
- มี pull request สำหรับเพิ่มการรองรับ MySQL ด้วย
Bun.sqlรัน SQL ด้วย tagged-template literal- ส่งค่า JavaScript เป็น SQL parameter ได้
- ใช้การ escape string และ prepared statement โดยอัตโนมัติเพื่อป้องกัน SQL injection
- ผลลัพธ์ส่งกลับเป็น array ของ object ที่ใช้ชื่อคอลัมน์เป็น key
- ใช้ implementation แบบ native code และการปรับแต่งหลายอย่าง
- prepared statement อัตโนมัติ
- query pipelining
- binary wire protocol
- connection pooling
- structure caching
- อ่าน row ได้เร็วขึ้นสูงสุด 50% เมื่อเทียบกับการใช้ Postgres client ยอดนิยมบน Node.js
- API ได้แรงบันดาลใจจาก
postgres.jsและออกแบบมาให้ย้ายโค้ดเดิมมาใช้ SQL client ในตัวของ Bun ได้ง่าย
การเปลี่ยนแปลงของตัวจัดการแพ็กเกจ
- Bun 1.2 เปลี่ยน lockfile เริ่มต้นจากไบนารี
bun.lockbเป็นแบบข้อความbun.lockbun.lockbเคยช่วยให้bun installเร็วกว่าnpmเกือบ 30 เท่า แต่ดูเนื้อหาบน GitHub ได้ยาก และทำให้การรีวิว pull request กับการแก้ merge conflict ทำได้ลำบาก- เครื่องมืออย่าง Dependabot ก็อ่าน lockfile ได้ยากเช่นกัน
bun.lockเป็นไฟล์ JSONC- รองรับคอมเมนต์และ trailing comma
- ตรวจดู diff ใน pull request ได้ง่ายขึ้น และ trailing comma ช่วยลดโอกาสเกิด merge conflict
- โปรเจกต์ใหม่จะสร้าง
bun.lock- โปรเจกต์เดิมที่ใช้
bun.lockbจะยังรองรับ lockfile แบบไบนารีต่อไปโดยไม่มีการไมเกรตอัตโนมัติ bun.lockbจะได้รับการรองรับระยะยาว และbun add,bun updateก็ยังอัปเดตไฟล์นี้ต่อไป- สามารถไมเกรตเป็น lockfile แบบข้อความใหม่ได้ด้วย
bun install --save-text-lockfile
- โปรเจกต์เดิมที่ใช้
bun installหลังเปลี่ยนมาใช้ lockfile แบบข้อความยัง เร็วกว่า Bun 1.1 อยู่ 30%- สามารถใช้คอมเมนต์และ trailing comma ใน
package.jsonได้require()และimport()ก็อ่านpackage.jsonแบบนี้ได้เช่นกัน- เนื่องจากยังไม่ใช่ฟีเจอร์ที่รองรับอย่างแพร่หลายในอีโคซิสเต็ม JavaScript ทั้งหมด จึงแนะนำให้ใช้แบบ “at your own risk”
- เพิ่มการรองรับ
.npmrc- อ่าน
.npmrcในรูทของโปรเจกต์และโฮมไดเรกทอรี - ใช้ตั้งค่า registry, scoped package และการยืนยันตัวตนสำหรับ private registry ได้
- อ่าน
- คำสั่งและตัวเลือกใหม่ของตัวจัดการแพ็กเกจ
bun run --filter: รันสคริปต์เดียวกันพร้อมกันในหลาย workspacebun outdated: ตรวจสอบ dependency ที่ล้าสมัยbun publish: ทางเลือกแทนnpm publishรองรับการยืนยันตัวตนผ่าน.npmrc, การแพ็ก tarball, OTP และการจัดการ edge case ของ package.jsonbun patch: บันทึกการแก้ไข dependency เป็นไฟล์.patchในpatches/และนำไปใช้โดยอัตโนมัติเมื่อรันbun install--omit=dev|optional|peer: ไม่ติดตั้ง dependency ประเภท dev, optional, peer- ตั้งค่าใบรับรอง CA ได้จาก
bunfig.toml, แฟล็ก CLI และ.npmrc - รองรับ
bundleDependenciesและการคงรูปแบบการย่อหน้าในpackage.jsonของbun addด้วย
การปรับปรุง test runner
bun testรองรับ JUnit XML reporter- ส่งผลการทดสอบไปยังเครื่องมือ CI/CD เช่น Jenkins, CircleCI, GitLab CI ได้ด้วย
bun test --reporter=junit --reporter-outfile=junit.xml - ตั้งค่า JUnit reporting ใน
bunfig.tomlได้เช่นกัน
- ส่งผลการทดสอบไปยังเครื่องมือ CI/CD เช่น Jenkins, CircleCI, GitLab CI ได้ด้วย
- เพิ่ม reporter แบบ LCOV สำหรับ code coverage
- สร้าง
coverage/lcov.infoได้ด้วยbun test --coverage --coverage-reporter=lcov - เปลี่ยนไดเรกทอรีเอาต์พุตได้ด้วย
--coverage-dir
- สร้าง
- รองรับ inline snapshot ผ่าน
expect().toMatchInlineSnapshot()- อัปเดต snapshot ภายในไฟล์ทดสอบด้วย
bun test -uหรือ--update-snapshots - ใช้
toThrowErrorMatchingSnapshot()และtoThrowErrorMatchingInlineSnapshot()ได้ด้วย
- อัปเดต snapshot ภายในไฟล์ทดสอบด้วย
test.only()ทำงานได้แล้วแม้ไม่มีแฟล็ก--only- API
expect()เพิ่ม matcher แบบเดียวกับ Jest, Vitest และjest-extended- กลุ่ม
toContainValue(),toContainKey(),toHaveReturned() - ส่งข้อความ error แบบกำหนดเองเป็นอาร์กิวเมนต์ตัวที่สองได้
- กลุ่ม
- ใช้
jest.setTimeout()และsetDefaultTimeout()เพื่อเปลี่ยน timeout เริ่มต้นของการทดสอบใน scope หรือ module ปัจจุบันได้
ฟีเจอร์ bundler และ build
- Bun 1.2 รองรับ HTML import
- เมื่อนำไฟล์ HTML ส่งให้ตัวเลือก
staticของBun.serveระบบจะ bundle<script>และ<link>ใน HTML โดยอัตโนมัติและเปิดเป็น static route
- เมื่อนำไฟล์ HTML ส่งให้ตัวเลือก
bun build --compileรองรับ cross compilation- สร้างไบนารี Windows หรือ macOS จาก Linux ได้ และทำในทางกลับกันได้ด้วย
- ใน build สำหรับ Windows สามารถตั้งค่าไอคอนและใช้ตัวเลือกซ่อนหน้าต่างคอนโซลได้
bun build --bytecodeสร้าง bytecode cache- ทำให้เวลาเริ่มต้นของแอปพลิเคชันอย่าง
eslintเร็วขึ้นได้ 2 เท่า - ไฟล์
.jscเก็บ bytecode cache ของไฟล์.jsที่เกี่ยวข้อง และต้องมีทั้งสองไฟล์จึงจะรันได้ - bytecode cache อาจมีขนาดใหญ่กว่าซอร์สโค้ด 8 เท่า จึงแลกการลดเวลาเริ่มต้นกับการใช้พื้นที่ดิสก์มากขึ้น
- ทำให้เวลาเริ่มต้นของแอปพลิเคชันอย่าง
- ระบุรูปแบบเอาต์พุตเป็น CommonJS ได้ด้วย
bun build --format=cjs- ก่อนหน้านี้รองรับเฉพาะ ESM
- ทำให้สร้างไลบรารีหรือแอปพลิเคชันสำหรับ Node.js เวอร์ชันเก่าได้ง่ายขึ้น
- ปรับปรุงการตรวจจับ CommonJS
- เมื่อไฟล์มีความกำกวม จะใช้ directive
"use strict"ด้านบนเป็น heuristic สุดท้ายของ CommonJS require.main === moduleจะถูกเขียนใหม่เป็นimport.meta.mainเพื่อให้ใช้ร่วมกับคำสั่ง import ได้
- เมื่อไฟล์มีความกำกวม จะใช้ directive
- Plugin API เพิ่ม hook
onBeforeParse()- ต้อง implement ด้วย N-API addon ไม่ใช่ JavaScript
- จัดการซอร์สโค้ดก่อนการ parse ได้แทบไม่มี overhead ในภาษา compiled เช่น Rust, C/C++, Zig
- เป็น API ขั้นสูงสำหรับผู้เขียน plugin และ framework
- ขยายตัวเลือก build ด้วย
- inject environment variable เข้า bundle ด้วย
--env="PUBLIC_*" - ลบการเรียกฟังก์ชันด้วยวิธีอย่าง
--drop=console - เพิ่ม banner/footer
- ตรวจดูรายการไฟล์ที่รวมอยู่ใน standalone executable ได้ด้วย
Bun.embeddedFiles() - เมิน dead-code elimination annotation ที่ไม่ถูกต้องด้วย
--ignore-dce-annotations - ตั้งค่าไม่ให้รวม dependency ของแพ็กเกจเข้า bundle ด้วย
--packages=external
- inject environment variable เข้า bundle ด้วย
การ bundle CSS
- Bun 1.2 implement CSS parser และ bundler ใหม่
- สืบทอดจากงานของ LightningCSS และเขียนใหม่จาก Rust เป็น Zig เพื่อผสานกับ JavaScript/TypeScript parser, bundler และ runtime ของ Bun
- ใช้
bun build ./index.cssเพื่อรวมไฟล์ CSS หลายไฟล์ รวมถึงการอ้างอิง@import,url,@font-faceเป็นไฟล์ CSS เดียวได้ - import ไฟล์
.cssจากโค้ด JavaScript และ TypeScript ได้- CSS ที่ import จาก JavaScript module graph และกฎ
@importจะถูก flatten เป็นไฟล์ CSS เดียวต่อ entrypoint
- CSS ที่ import จาก JavaScript module graph และกฎ
- ใช้ API
Bun.build()เพื่อ bundle CSS และ JavaScript ผ่าน API เดียวกันได้
เพิ่ม API ของ Bun runtime
Bun.serve()รองรับ static route ผ่านพร็อพเพอร์ตีstatic- ส่ง path เป็น key และอ็อบเจ็กต์
Responseเป็น value - static route เร็วกว่าการจัดการโดยตรงใน handler ของ
fetch()ได้สูงสุด 40% - response body, header และ status code ถูก cache ไว้ในหน่วยความจำ จึงไม่มี JavaScript allocation และ garbage collection
- สามารถ reload static route ได้ด้วย
server.reload()
- ส่ง path เป็น key และอ็อบเจ็กต์
Bun.udpSocket()ให้ UDP socket ในรูปแบบ Bun API- แม้จะรองรับ
node:dgramด้วย แต่Bun.udpSocket()เป็น API สมัยใหม่ที่คล้ายกับBun.listen()เดิม - สามารถส่ง UDP datagram หลายรายการด้วย syscall เดียว และรับมือกับ OS backpressure ได้
- แม้จะรองรับ
Bun.file()รองรับdelete(),unlink(),stat()stat()คืนค่า metadata ในรูปแบบเดียวกับอ็อบเจ็กต์Statsของ Node.jsfs.stat()- ใช้ API เดียวกันกับไฟล์ S3 ได้ด้วย
Bun.color()ให้การ parse, normalize และแปลงค่าสี- รองรับ CSS, ANSI color code, RGB, HSL เป็นต้น
dns.prefetch()สามารถดึง DNS record ไว้ล่วงหน้าเพื่ออุ่น DNS cache ตอนเริ่มต้นได้- ตรวจสอบสถานะ DNS cache ได้ด้วย
dns.getCacheStats()
- ตรวจสอบสถานะ DNS cache ได้ด้วย
- utilities อื่น ๆ
Bun.inspect.table(): คืนค่าสตริงรูปแบบตารางเหมือนconsole.tableBun.randomUUIDv7(): สร้าง monotonic UUID v7 ที่เหมาะกับการเรียงลำดับและฐานข้อมูล
ปรับปรุง SQLite client
- SQLite client ในตัวของ Bun สามารถ map ผลลัพธ์ query เป็น class instance ได้ด้วย
query.as(Class)- เพิ่ม getter, setter และ method ได้
- ด้วยเหตุผลด้านประสิทธิภาพ จึงไม่รองรับ class constructor, default initializer และ private field
- ไม่ใช่ ORM เพราะไม่ได้จัดการ relation หรือสร้าง SQL ให้
query.iterate()ประมวลผลแถวด้วย iterator โดยไม่โหลดทุกแถวขึ้นหน่วยความจำพร้อมกัน- ตัวอ็อบเจ็กต์ query เองก็วนด้วยลูป
forได้
- ตัวอ็อบเจ็กต์ query เองก็วนด้วยลูป
- เมื่อเปิดตัวเลือก
strictสามารถละ prefix$,@,:ใน query parameter ได้- หาก parameter ขาดหายไป จะ throw error
- ตรวจสอบจำนวนแถวที่เปลี่ยนแปลงและ row ID ล่าสุดที่ insert ได้จากผลลัพธ์ของ
db.run()changeslastInsertRowid
- ตัวเลือก
safeIntegersคืนค่าจำนวนเต็ม 64 บิตเป็นBigIntแทนnumberที่ถูกตัดทอน- ตั้งค่าได้ทั้งระดับ database หรือระดับ query
- สามารถใช้ syntax
usingของ JavaScript เพื่อ close statement และ database โดยอัตโนมัติเมื่อจบ scope
คอมไพล์และรัน C จาก JavaScript
- Bun 1.2 เพิ่ม การรองรับแบบทดลอง สำหรับคอมไพล์และรัน C จาก JavaScript
- ใช้ API
cc()ของbun:ffi - เป็นวิธีใช้ C system library จาก JavaScript โดยไม่ต้องมี build step แยกต่างหาก
- ใช้ API
- Bun มี
tinyccในตัว- ต่างจาก
gccหรือclangตรงที่สามารถคอมไพล์โค้ด C ง่าย ๆ ได้ในระดับมิลลิวินาที - สามารถคอมไพล์และรันโค้ด C เมื่อจำเป็นได้
- ต่างจาก
- รองรับโค้ด C ที่ใช้ N-API ด้วย
- ทำงานได้ด้วย Bun เพียงอย่างเดียว โดยไม่ต้องมีขั้นตอน build ของ
node-gyp
- ทำงานได้ด้วย Bun เพียงอย่างเดียว โดยไม่ต้องมีขั้นตอน build ของ
รองรับ musl และ Alpine Linux
- Bun 1.2 เพิ่ม build ของ Bun สำหรับ Linux distribution ที่ใช้ musl libc แทน glibc
- ใช้ได้ในสภาพแวดล้อมอย่าง Alpine Linux
- รองรับ Linux x64 และ aarch64
- บน Docker สามารถใช้ image
oven/bun:alpineได้ - musl ช่วยให้ container image มีขนาดเล็กลง แต่มีแนวโน้มว่าจะช้ากว่า Bun เวอร์ชัน glibc เล็กน้อย
- หากไม่มีเหตุผลเฉพาะ แนะนำให้ใช้ glibc
ฟีเจอร์ภาษา JavaScript
- เพิ่มการรองรับ import attributes
- สามารถระบุ JSON, text, TOML ฯลฯ ตอน import ได้ เช่น
import json from "./package.json" with { type: "json" } - ใช้กับ
import()แบบ dynamic ได้ด้วย
- สามารถระบุ JSON, text, TOML ฯลฯ ตอน import ได้ เช่น
- รองรับ
usingและawait using- เมื่อออกจาก scope จะเรียก
[Symbol.dispose]หรือ[Symbol.asyncDispose]เพื่อจัดการ resource โดยอัตโนมัติ - รองรับใน Bun API หลายตัว เช่น
Bun.spawn(),Bun.serve(),Bun.connect(),Bun.listen(),bun:sqlite
- เมื่อออกจาก scope จะเรียก
- API ใหม่เกี่ยวกับ Promise
Promise.withResolvers(): สร้างpromise,resolve,rejectพร้อมกันPromise.try(): ห่อฟังก์ชันแบบ synchronous หรือ asynchronous ให้เป็น promise
- API สำหรับ error และ byte array
Error.isError(): ตรวจสอบว่าเป็น Error ได้แม่นยำขึ้น แม้ในกรณีที่มีการแก้ prototype chain หรือสถานการณ์ cross-realm ของnode:vmUint8Array.toBase64()/Uint8Array.fromBase64()Uint8Array.toHex()/Uint8Array.fromHex()
- เพิ่ม iterator helper
map,flatMap,filter,take,drop,reduce,toArray,forEach,find
- รองรับ
Float16Array- array ของ floating point 16 บิตมีความแม่นยำน้อยกว่า 32 บิต แต่ใช้หน่วยความจำมีประสิทธิภาพกว่า
เพิ่ม Web API
- รองรับ
TextDecoderStreamและTextEncoderStream- เป็นเวอร์ชัน streaming ของ
TextDecoderและTextEncoder - ใน Bun,
TextEncoderStreamเร็วกว่า Node.js ได้สูงสุด 30 เท่า
- เป็นเวอร์ชัน streaming ของ
- รองรับตัวเลือก
streamของTextDecoder- แม้ chunk จะไม่ใช่ UTF-8 code point ที่สมบูรณ์ ก็สามารถประมวลผลเป็นส่วนหนึ่งของ stream ที่ใหญ่กว่าได้
- เพิ่มเมธอด
bytes()- คืนค่า stream data เป็น
Uint8ArrayจากResponse,Blob,Bun.file()เป็นต้น - ลดขั้นตอนเดิมที่ต้อง
arrayBuffer()แล้วสร้างUint8Array
- คืนค่า stream data เป็น
- รองรับ streaming upload ด้วย
fetch()- มีประโยชน์สำหรับอัปโหลดไฟล์ขนาดใหญ่หรือ stream data ที่ไม่รู้ content length ล่วงหน้า
- implement
console.group()และconsole.groupEnd() - รองรับ
URL.createObjectURL()- สร้าง URL จาก
Blobแล้วใช้กับfetch(),Worker,import()ได้ - Worker script ก็ผ่าน Bun transpiler เช่นกัน จึงใช้ syntax ของ TypeScript ได้
- สร้าง URL จาก
AbortSignal.any()รวมAbortSignalหลายตัวเข้าด้วยกัน ทำให้เมื่อมีตัวใดตัวหนึ่ง abort แล้ว signal หลักก็ abort ด้วย
การเปลี่ยนแปลงพฤติกรรมและข้อควรระวังในการไมเกรต
- ไดเรกทอรีทำงานของ
bun runเปลี่ยนไป- ก่อนหน้านี้จะใช้ไดเรกทอรีทำงานปัจจุบันของ shell
- ใน Bun 1.2 จะใช้ไดเรกทอรีแม่ของ
package.jsonเป็นไดเรกทอรีทำงานของสคริปต์ - เป็นการเปลี่ยนแปลงเพื่อให้สอดคล้องกับพฤติกรรมของ
npmและyarn
bun testจะรายงาน uncaught error หรือ rejection ระหว่างการทดสอบเป็นความล้มเหลว- ก่อนหน้านี้ข้อผิดพลาดลักษณะนี้อาจไม่ถูกจัดเป็นการทดสอบล้มเหลว
- ตอนนี้
server.stop()คืนค่าPromise<void>- สามารถรอจนกว่า in-flight HTTP connection จะปิดได้
- เมื่อ
Bun.build()ล้มเหลว จะ reject แทนการใส่ข้อผิดพลาดไว้ในlogsของผลลัพธ์ที่ resolve แล้ว- หากต้องการพฤติกรรมเดิม สามารถตั้งค่า
throw: falseได้
- หากต้องการพฤติกรรมเดิม สามารถตั้งค่า
bun -pกลายเป็น alias ของbun --printเพื่อให้สอดคล้องกับ Node.js- ก่อนหน้านี้เป็น alias ของ
bun --port
- ก่อนหน้านี้เป็น alias ของ
- ค่าเริ่มต้นของ
bun build --sourcemapเปลี่ยนจาก inline source map เป็น linked source map- หากต้องการพฤติกรรมเดิม ให้ใช้
--sourcemap=inline
- หากต้องการพฤติกรรมเดิม ให้ใช้
การปรับปรุงประสิทธิภาพ
- Bun 1.2 มี การปรับปรุงประสิทธิภาพ ในหลายเส้นทางการทำงาน
node:http2: เร็วขึ้น 2 เท่า- การอัปโหลด S3 ผ่าน
node:http: เร็วขึ้น 5 เท่า path.resolve(): เร็วขึ้น 30 เท่า- การทำ DNS resolution ของ
fetch(): เร็วขึ้น 2 เท่า bun --hot: ใช้หน่วยความจำลดลง 2 เท่าfs.readdirSync()บน macOS: อ่านไดเรกทอรีขนาดเล็กเร็วขึ้น 5%String.at(): เร็วขึ้น 44%atob()สำหรับอินพุตสตริงขนาดใหญ่: เร็วขึ้นสูงสุด 8 เท่า- การคลายการบีบอัดข้อมูล gzip ของ
fetch(): เร็วขึ้น 30% Buffer.from(string, "base64")สำหรับอินพุตขนาดใหญ่: เร็วขึ้น 6–30 เท่าJSON.parse()สำหรับอินพุตสตริงขนาดใหญ่: เร็วขึ้น 2–4 เท่า, อินพุต object เร็วขึ้น 6%- throughput ของแอปพลิเคชัน
Bun.serve()บางส่วน: เพิ่มขึ้นสูงสุด 2 เท่า Error.captureStackTrace(): เร็วขึ้น 9 เท่าfs.readFile()สำหรับไฟล์ขนาดเล็ก: เร็วขึ้นสูงสุด 10%console.log()ที่รับอาร์กิวเมนต์เป็นสตริง: เร็วขึ้น 50%
- บน Windows เปิดใช้งาน JIT ของ JavaScriptCore แล้ว
- ก่อนหน้านี้ JIT ใช้ได้เฉพาะบน macOS และ Linux
- JavaScript บน Windows โดยรวมจะทำงานเร็วขึ้น
- ตัวอย่างเช่น
Object.entries()เร็วขึ้น 20% และArray.map()เร็วขึ้น 50%
การติดตั้งและอัปเกรด
- คำสั่งติดตั้งใหม่
curl -fsSL https://bun.sh/install | bashpowershell -c "irm bun.sh/install.ps1 | iex"npm install -g bun- หลังจาก
brew tap oven-sh/bunให้ใช้brew install bun docker pull oven/bun
- Bun ที่ติดตั้งไว้แล้วให้อัปเกรดด้วย
bun upgrade
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ไม่เข้าใจว่าทำไมถึงเอา ฐานข้อมูลของบุคคลที่สาม กับ ไลบรารี S3 ภายนอก ใส่ไว้ใน core/standard library
ของแบบนี้น่าจะเหมาะเป็นไลบรารีให้เลือกใช้มากกว่า และ runtime แบบนี้ควรคัดเลือกสิ่งที่จะใส่ใน standard library อย่างระมัดระวังมาก
เริ่มให้ความรู้สึกเหมือนโปรเจกต์ที่ใส่ทุกอย่างสารพัดลงไปเหมือนอ่างล้างจานในครัวแล้ว
แนวทางแบบ มีแบตเตอรี่ให้ครบ เป็นแนวทางที่ได้รับความนิยมและถูกเลือกใช้ในหลายที่
การตั้งค่า TypeScript ก็ยาก Webpack, S3, Postgres, Jest ก็เช่นกัน ดังนั้นการเข้าถึงไฟล์และสตรีมที่เรียบง่ายขึ้นก็น่าสนใจพอสมควร
คงต้องรอดูว่าผู้ให้บริการ deploy แบบกระจายจะออกมาอย่างไร
แน่นอนว่าอาจเดาผิดก็ได้ แต่การเอา dependency แบบนี้ใส่ใน core/standard library จริง ๆ แล้วไม่ค่อยสมเหตุสมผล
ดูเหมือนเขามองว่าถ้าใส่ไว้ใน core จะ optimize ได้ดีกว่าไลบรารีของบุคคลที่สาม
ส่วนตัวคิดว่าเป็นแนวทางที่ผิด และรู้สึกว่า Jared มีความทะเยอทะยานมากเกินไป แต่สุดท้ายมันก็เป็นโปรเจกต์ที่เขาทุ่มเทด้วยใจจริง ๆ
ตามคำอธิบายของฝั่ง Bun คือ “Bun มุ่งเป็น JavaScript runtime ที่ให้ความสำคัญกับคลาวด์ก่อน กล่าวคือรองรับเครื่องมือและบริการทั้งหมดที่จำเป็นสำหรับการรันแอปพลิเคชัน production บนคลาวด์” แต่คำพูดนี้ไม่ได้ทำให้รู้สึกน่าเชื่อถือเท่าไร
การตัดสินใจด้านการออกแบบเฉพาะจุดนี้ดู แย่กว่า Node เสียอีก
ปัญหาของซอฟต์แวร์ที่มี VC หนุนหลังมักเป็นแบบนี้เสมอ คือฟีเจอร์ผสานรวมเหล่านี้พยายามจะนำเสนออะไรบางอย่างที่เป็นเอกลักษณ์ หรือพูดอีกอย่างคือพยายามสร้างการผูกติด
ประสบการณ์ใช้ Bun ที่ผ่านมาดีมาก
เวลาตั้งค่า TypeScript/Jest/React/Webpack ในโปรเจกต์ใหม่ ผมมักเลี่ยงเพราะมี breaking changes จากหลายทางตลอด แต่ใน Bun มันจัดการได้เอง และสำหรับ use case ของผมก็ใช้งานได้เลยโดยไม่เจ็บปวด
การผสานรวมไลบรารีของบุคคลที่สามอย่าง S3, SQL นั้นพูดยาก แต่ดูเหมือนอย่างน้อยก็โฟกัสสิ่งที่ใช้กันแพร่หลายที่สุดและมีคนขอมากที่สุด
ดีที่มันนำความเป็นปกติที่ ระบบนิเวศเครื่องมือของ Node.js ต้องการกลับมาให้
ดูเหมือนจะประเมินต่ำไปว่าเครื่องมืออื่น ๆ ก็พัฒนาขึ้นมากในช่วงที่ผ่านมาเหมือนกัน
สำหรับผมมันเหมือน สูตรโกงด้าน productivity
แม้จะมี productivity loss เล็กน้อยเพราะ ChatGPT ไม่ค่อยรู้จัก Bun ดี แต่ก็ยังชอบ Bun อยู่ดี
มีหลายอย่างที่ดี แต่กังวลว่าพฤติกรรมเริ่มต้นบางส่วนจะกลายเป็น พฤติกรรมที่ซ่อนอยู่เหมือนเวทมนตร์ มากเกินไปหรือเปล่า
ถ้าใช้
new Response(s3.file(...))แทนที่ Bun จะดาวน์โหลดไฟล์ S3 มายังเซิร์ฟเวอร์แล้วส่งให้ผู้ใช้ Bun จะ redirect ผู้ใช้ไปยัง presigned URL ของไฟล์ S3ในฐานะค่าเริ่มต้นถือว่าเป็นทางเลือกที่ค่อนข้างน่าประหลาดใจ และก็ไม่ชัดเจนเลยว่าจะปิดอย่างไรเมื่อไม่อยาก expose bucket S3 โดยตรง
ตอนแรกผมคาดหวังกับโปรเจกต์นี้ แต่เมื่อเห็นการตัดสินใจด้านการออกแบบที่กระจัดกระจายและส่วนตัวมักคิดว่าไม่ดีซึ่งถูกเปิดเผยบนโซเชียล ก็ทำให้ไม่มั่นใจในทิศทางระยะยาว
ถ้ายังอยู่ที่ v0.x ก็คงโอเค แต่เมื่อออก 1.0 แล้ว มาตรฐานในการเพิ่ม API surface ควรสูงกว่านี้มาก
Response(file.stream())ส่วนตัวรู้สึกเหมือนเป็น พฤติกรรมที่มี side effect แรง และเวลาอ่านดูเหมือนจะคืนเนื้อหาไฟล์ ไม่ใช่ URL
ถึงอย่างนั้นก็สงสัยเหมือนกันว่าการ expose bucket มันน่ารำคาญตรงไหน
เพราะเป็น presigned URL ไม่ได้ให้สิทธิ์เข้าถึงแบบกว้าง ๆ
API ที่ชัดเจนอย่าง
Response((file(...).getPresignedURL()))น่าจะดีกว่า หรือไม่ก็มีตัวเลือกให้เปิดพฤติกรรมนี้ผ่าน environment variable หรือการตั้งค่า Bun น่าจะเหมาะกว่ารวมแบตเตอรี่ในตัว สร้างความแตกต่างได้มาก
นี่เป็นเหตุผลที่ชอบที่เว็บ API อย่าง Fetch API, Service Workers, Web Components, ES6+, WebRTC ตอนนี้กลายเป็นของเนทีฟทั้งในรันไทม์ V8 และ WebKit
แต่ก็ต้องมีขอบเขต
S3 อาจจะไปไกลเกินไป แต่ไดรเวอร์ SQL นั้นสมเหตุสมผล
ถึงอย่างนั้น ปัญหาคือจะใส่เข้าไปถึงไหน
ฐานข้อมูลมีเยอะมาก แล้วต้องใส่ไดรเวอร์ของครึ่งหนึ่งในนั้นด้วยไหม?
แค่ถึงระดับนั้นก็มีโค้ดเพิ่มขึ้นมากพอที่จะทำให้ไฟล์ executable ช้าลงได้
อีกอย่าง การใส่ API ที่อ่อนไหวแบบนี้ไว้ใน Bun ก็อาจทำให้พลาดเรื่องความปลอดภัยได้
ลองจินตนาการว่าสคริปต์บางตัวหรือปัญหาเรื่อง path ทำให้
evalถูกรัน แล้ว Bun อัปโหลดซอร์สไฟล์ทั้งหมดไปยัง S3 ส่วนตัว เท่านั้นก็จบแล้วเคยเห็นว่าขึ้นอยู่กับวิธีที่โค้ดถูกโหลดตอนรันไทม์ มันอาจแทบมองข้ามได้
ถ้าการโหลดโค้ดถูก trigger เฉพาะเมื่อเห็นคำสั่ง
importงั้นแทบไม่มี overhead ด้านความเร็วเลยไม่ใช่หรือ?ต่อให้ลิงก์แบบ static ก็ยังไม่ค่อยเข้าใจว่าทำไมแค่มีโค้ดอยู่จึงทำให้ไฟล์ executable ช้าลงในระดับที่ควรคำนึงถึง
อาจมีแค่ขนาดไฟล์ executable ที่ต้องโหลดเข้า memory ใหญ่ขึ้นตามตัวอักษร แต่ไม่น่าจะเป็นความช้าลงที่รู้สึกได้
แก่นคือใครเป็นผู้รับผิดชอบดูแลไลบรารี และเมื่อ SQLite เปลี่ยน จะเปลี่ยนไลบรารีนั้นอย่างไร
ถ้า SQLite มีบั๊ก ใน Bun จะแก้อย่างไร?
ต้องแก้ในเวอร์ชันไหนบ้าง?
แพตช์ของรันไทม์อาจเปลี่ยนพฤติกรรมของโค้ดที่รันอยู่บนมัน แล้วจะจัดการอย่างไรถ้าผู้ใช้ทำ workaround ไว้ให้เข้ากับพฤติกรรมเดิมแล้ว?
ในระดับหนึ่งเป็นปัญหาที่แก้ได้ แต่ก็มีข้อเสียตามมา
เมื่อถึงจุดหนึ่ง มันจะไม่ใช่รันไทม์ แต่กลายเป็น แพลตฟอร์ม และมาพร้อมความรับผิดชอบกับปัญหาแบบอื่น
ไม่ใช่มาตรฐานเว็บจริง ๆ แต่ก็เป็นสิ่งที่คนจำนวนมากปรับให้เข้ากันและใช้เหมือนเป็นมาตรฐานโดยพฤตินัย
ช่วงนี้ลูกค้าใช้ Bun ใน production
ได้ยินมาว่า developer experience ของ Bun ดีแบบเหลือเชื่อเพราะความเร็วและความเรียบง่าย
developer experience มีบทบาทใหญ่ในระยะยาว
ถ้า codebase หรือ process เละเทะ ก็จะเสียคนเก่ง ๆ ไป เว้นแต่จะให้ค่าตอบแทนระดับ FAANG
ยังไม่เคยลองใช้ Bun แต่รายการฟีเจอร์ยาวมากจนสงสัยว่าทั้งหมดจะแข็งแรงและไม่มีบั๊กจริงหรือไม่
หวังว่าจะคิดผิด และตั้งใจจะลองรันในโปรเจกต์ภายหลัง
จากมุมมองการจัดการโปรเจกต์ ค่อนข้างสับสนว่าทำไมถึงเอาเวลาไปทำการรองรับ S3 ทั้งที่ยังไม่ได้ เข้ากันได้กับ Node.js 100%
Next.js เป็น ecosystem ที่ใหญ่มาก ถ้าดึงลูกค้า Next.js มาได้ ก็น่าจะเติบโตได้มากกว่าการรองรับ S3 มาก
ในชีวิตประจำวัน คุณใช้ พื้นผิว API ของ Node.js ทั้งหมดจริง ๆ แค่ไหน?
และพึ่งพา edge case แปลก ๆ ในนั้นจริง ๆ แค่ไหน?
คนที่ทำงานอยู่ก็ไม่ใช่หุ่นยนต์
บางงานต้องใช้เวลาในการทำความเข้าใจ และระหว่างนั้นก็ทำงานอื่นได้
ไม่ใช่ว่าคนเดียวทำทุกอย่าง
บอกว่า “ถ้าดึงลูกค้า Next.js มาได้จะเติบโตมากขึ้น” แต่เติบโตไปสู่อะไร?
นั่นไม่ได้ทำเงิน
นี่เป็นโปรเจกต์ที่ได้รับการสนับสนุนจาก VC และเป้าหมายไม่ใช่การแจก Bun ฟรีเพื่อให้ได้ผู้ใช้ทั้งโลก
Zig มีความปลอดภัยด้านหน่วยความจำต่ำมาก
ถ้าอ้างอิงตัวแปรที่ไม่ยังมีชีวิตอยู่แล้ว มันจะเข้าถึงหน่วยความจำอื่นที่ไม่เกี่ยวข้องแบบสุ่มแทนที่จะเกิด segmentation fault
ว่ากันว่าเป็นแบบนั้นแม้ใน debug และ safe mode[0]
การวางระบบ lifetime ของหน่วยความจำไว้ด้านบน ที่ทำเครื่องหมายชื่อตัวแปรว่า dead แล้วห้ามเข้าถึงถ้ามันตายแล้ว มันยากขนาดนั้นเลยหรือ?
สุดท้ายก็กลายเป็น “อย่าใช้ undefined behavior”[1]
เพราะงั้นจึงไม่อยากวางอะไรที่ทำด้วย Zig ไว้ในที่อย่างเว็บเซิร์ฟเวอร์ที่เปิดสู่ internet
[0] : https://news.ycombinator.com/item?id=41720995
[1] : https://github.com/ziglang/zig/issues/16467#issuecomment-164...
เคยลองใช้ปีที่แล้ว แล้วมัน crash อยู่เรื่อย ๆ
bun addไม่รักษาช่องว่างและ indentation ในpackage.jsonแล้ว ตอนนี้รักษาได้แม้ indentation จะแปลกแค่ไหน นี่ค่อนข้างขำไม่รู้ว่าใครขอสิ่งนี้ และทำไมถึงคิดว่าคุ้มค่าที่จะเขียนโค้ดเพื่อมัน
การนำเข้า HTML นั้นยอดเยี่ยมและเท่มาก
ใน Bun 1.2 รองรับการนำเข้า HTML แล้ว และบอกว่าสามารถแทนที่ toolchain ฝั่ง frontend ทั้งหมดได้ด้วยคำสั่ง
importเพียงคำสั่งเดียวเริ่มได้โดยส่งการนำเข้า HTML ให้กับตัวเลือก
staticของBun.serveสามารถโหลดปลั๊กอินเฉพาะเฟรมเวิร์กอย่าง hot module replacement, CSS preprocessing, Vue SFC compiler ได้ไหม?
การเสิร์ฟไฟล์ static ไม่ใช่เรื่องใหม่อะไร เลยรู้สึกเหมือนว่าผมอาจพลาดอะไรไป
ผมเคยคิดว่าไม่มีโปรเจกต์ไหนที่ถูกลิขิตให้ล้มเหลวเท่ากับทางเลือกคู่แข่งของ Node.js แล้ว แต่พอได้ลองใช้ดูก็ถือว่าคิดถูกที่ลอง
ผมต้องทำสคริปต์แบบสแตนด์อโลนจำนวนมากสำหรับจัดการอัปเดตไฟล์ข้อความและฐานข้อมูล SQLite และสามารถใช้ TypeScript,
bun:sqlite[1],bun $ Shell[2] ได้ทันทีโดยไม่ต้องมีไฟล์คอนฟิกหรือจัดการ dependency ของ npm แบบโลคัลหลังจากนั้นก็ลองใช้กับโปรเจกต์ JS/TypeScript ใหม่ ๆ ด้วย ซึ่งได้ใช้ทั้ง bundler ในตัว [3] และการรองรับการทดสอบ [4] แถมติดตั้ง dependency เสร็จแทบทันที
การที่ทุกอย่างทำงานได้ทันทีอย่างรวดเร็วนั้นเป็นการยกระดับคุณภาพชีวิตจริง ๆ และตอนนี้ Bun กลายเป็น ตัวเลือกแรก สำหรับโปรเจกต์ JS ใหม่ของผมแล้ว
[1] https://bun.sh/docs/runtime/shell
[2] https://bun.sh/docs/api/sqlite
[3] https://bun.sh/docs/bundler
[4] https://bun.sh/docs/cli/test
ผมเคยอยู่ฝั่งที่คิดว่า “ของพวกนี้ปีหน้าก็คงมีใน npm หมดแล้ว มันจะมีความหมายอะไร”
สุดท้ายได้ลองใช้ Bun แล้วก็ประหลาดใจจริง ๆ
เมื่อ รายละเอียดเล็ก ๆ ของประสบการณ์นักพัฒนา สะสมกัน มันสร้างความแตกต่างได้มาก
ในโปรเจกต์ของผม Bun ให้ความรู้สึกเหมือนเป็นเจเนอเรชันถัดไปจริง ๆ
เมื่อไม่นานมานี้ผมได้ลองใช้ Bun เป็นครั้งแรก และประสบการณ์ดีมาก
โปรเจกต์ทั้งหมดของผมตั้งค่า Webpack หรือ Vite ไว้เพื่อใช้ TypeScript และเมื่อตั้งค่าแล้วก็มักทำงานได้เกือบสมบูรณ์แบบ แต่การตั้งค่านั้นยุ่งยาก และไม่คุ้มสำหรับสคริปต์เล็ก ๆ
แต่ Bun กลับใช้งานได้ทันที
ตอนพยายามรัน TS “โดยตรง” จาก CLI ผมนั่งงมกับเครื่องมือที่ชื่อ
node-tsหรืออะไรทำนองนั้นอยู่ 10–30 นาที เจอข้อความชวนสยองอย่าง “ไม่ใช่โมดูล”, “ใช้ import/require ไม่ได้”, “ESM/CJS” และลองวิธีแก้ที่พบบ่อยทั้งหมดแล้ว ทั้งเปลี่ยนชนิดโมดูลในpackage.json, เปลี่ยนtsconfig, เปลี่ยนวิธีใช้import/requireพอกำลังจะรันสคริปต์ประมาณ 200 บรรทัด แล้วเปลี่ยนมาใช้ Bun เป็นทางเลือกสุดท้าย มันก็ทำงานได้อย่างยอดเยี่ยม
node --experimental-strip-types index.tsถ้าไม่ใช่ Node รุ่นล่าสุด แพ็กเกจ
tsxก็ทำงานได้ดีสำหรับผมดีกว่า
ts-nodeแต่ทั้งสองทางเลือกก็แค่ทิ้งข้อมูลชนิดไปเฉย ๆ และ Bun ก็เหมือนกัน
ชอบทิศทางนี้
โดยเฉพาะการใส่การรองรับ S3 และ Postgres แบบเนทีฟ เข้ามา เป็นสิ่งที่สมเหตุสมผลมาก เพราะมันสามารถเป็นทางเลือกให้กับสถานะปัจจุบันที่ต้อง “ประกอบ framework เอง” ได้
ในเว็บเฟรมเวิร์กแบบครบเครื่องอย่าง Rails และ Laravel ทั้งหมด สิ่งนี้เป็นมาตรฐานอยู่แล้ว และ ecosystem ของ JS ก็จะได้ประโยชน์มากจากตรงนี้
ผมมองว่าขั้นต่อไปคือ migration กับการจัดการ schema และประสบการณ์ทดสอบพื้นฐานที่ดีกว่า ซึ่งตั้งค่า factory ได้ดี