Memulai dengan Bun API

Mark Ponomarev

Mark Ponomarev

4 May 2025

Memulai dengan Bun API

Di antara alat pengembang terbaru yang paling menarik adalah Bun, sebuah toolkit JavaScript yang sangat cepat dan lengkap, dirancang untuk meningkatkan produktivitas pengembang dan kinerja aplikasi. Bun bukan sekadar runtime lain; ini adalah ekosistem yang kohesif yang mencakup runtime, bundler, test runner, package manager, dan lainnya, semuanya dalam satu executable native tunggal. Panduan ini akan memandu Anda melalui hal-hal penting tentang Bun, dengan fokus pada konsep inti dan API yang kuat.

💡
Ingin alat Pengujian API hebat yang menghasilkan Dokumentasi API yang indah?

Ingin platform All-in-One yang terintegrasi untuk Tim Pengembang Anda bekerja sama dengan produktivitas maksimum?

Apidog memenuhi semua permintaan Anda, dan menggantikan Postman dengan harga yang jauh lebih terjangkau!
button

Apa itu Bun?

Intinya, Bun dibangun di sekitar mesin runtime JavaScript berperforma tinggi. Berbeda dengan Node.js, yang menggunakan mesin V8 Google, Bun menggunakan JavaScriptCore (JSC) Apple, mesin yang mendukung Safari. Pilihan ini, dikombinasikan dengan implementasi Bun dalam bahasa pemrograman Zig tingkat rendah, berkontribusi signifikan terhadap kecepatannya yang luar biasa. Waktu startup untuk aplikasi Bun seringkali diukur jauh lebih cepat daripada aplikasi Node.js yang setara, terkadang dengan faktor empat atau lebih. Keunggulan kecepatan ini meluas melampaui startup; implementasi internal Bun dari berbagai API dioptimalkan untuk throughput maksimum dan penggunaan memori minimal.

Tetapi ambisi Bun melampaui sekadar menjadi runtime yang lebih cepat. Ini bertujuan untuk menjadi toolkit yang komprehensif, menangani kebutuhan pengembang umum secara langsung:

  1. Alat Terintegrasi: Perintah bun itu sendiri bertindak sebagai titik masuk untuk berbagai fungsi. bun run mengeksekusi skrip yang ditentukan dalam package.json, bun install mengelola dependensi (seringkali jauh lebih cepat daripada npm atau yarn), bun test menjalankan tes menggunakan API yang kompatibel dengan Jest, bun build menggabungkan kode untuk produksi, dan bunx mengeksekusi paket tanpa menginstalnya secara eksplisit. Integrasi ini menyederhanakan alur kerja dengan mengurangi jumlah alat pengembangan yang berbeda yang dibutuhkan.
  2. Dukungan Native TypeScript dan JSX: Salah satu fitur unggulan Bun adalah dukungan siap pakai untuk file TypeScript (.ts, .tsx) dan JSX (.jsx). Bun menyertakan transpiler bawaan yang sangat dioptimalkan yang menangani jenis file ini secara mulus selama eksekusi atau bundling. Ini menghilangkan kebutuhan untuk langkah kompilasi terpisah yang melibatkan tsc atau Babel untuk banyak skenario pengembangan umum, merampingkan proses pengaturan.
  3. Kompatibilitas Sistem Modul: Bun merangkul JavaScript modern dengan dukungan kelas satu untuk ES Modules (ESM). Namun, ia mengakui ekosistem luas yang ada yang dibangun di atas CommonJS (CJS). Bun menyediakan kompatibilitas yang kuat untuk kedua sistem modul, memungkinkan pengembang untuk menggunakan import dan require sebagian besar secara bergantian dan memanfaatkan jutaan paket CJS yang ada yang tersedia di npm.
  4. Kepatuhan API Standar Web: Prinsip desain utama adalah implementasi API Web standar. Fungsi dan objek seperti fetch, Request, Response, Headers, WebSocket, dan Streams API (ReadableStream, WritableStream) dibangun ke dalam cakupan global Bun. Ini mendorong portabilitas kode antara lingkungan Bun sisi server, frontend browser, dan platform komputasi edge, memungkinkan pengembang untuk menggunakan kembali API yang familiar di berbagai konteks.
  5. Kompatibilitas Node.js: Sementara menempuh jalannya sendiri dengan API yang dioptimalkan dan standar Web, Bun bertujuan untuk tingkat kompatibilitas yang tinggi dengan permukaan API Node.js. Banyak modul Node.js bawaan (node:fs, node:path, node:os, node:events, dll.) dan objek global (process, Buffer, __filename, __dirname) diimplementasikan sebagian atau seluruhnya. Tujuannya adalah untuk memungkinkan banyak proyek Node.js dan paket npm yang ada berjalan di Bun dengan sedikit atau tanpa modifikasi, memposisikan Bun sebagai "pengganti langsung" dalam banyak kasus.

Dengan menggabungkan elemen-elemen ini, Bun menghadirkan alternatif yang menarik bagi pengembang JavaScript dan TypeScript yang mencari kinerja, kesederhanaan, dan pengalaman pengembangan modern.

Cara Menginstal Bun

Memulai dengan Bun dirancang agar cepat dan mudah di berbagai platform. Metode paling umum untuk macOS, Linux, dan Windows Subsystem for Linux (WSL) menggunakan perintah curl sederhana yang dieksekusi di terminal Anda:

curl -fsSL https://bun.sh/install | bash

Perintah ini mengunduh skrip instalasi dan mengirimkannya langsung ke bash. Skrip menangani deteksi sistem operasi dan arsitektur Anda, mengunduh executable Bun yang sesuai, dan biasanya menginstalnya ke ~/.bun/bin. Ini juga mencoba memperbarui file konfigurasi shell Anda (seperti .zshrc, .bashrc, atau .bash_profile) untuk menambahkan ~/.bun/bin ke PATH sistem Anda, membuat perintah bun tersedia secara global. Anda mungkin perlu me-restart sesi terminal Anda atau secara manual me-source file konfigurasi shell Anda (misalnya, source ~/.zshrc) agar perubahan segera berlaku.

Jika Anda mengalami masalah izin atau lebih suka tidak mengirimkan langsung ke bash, Anda dapat mengunduh skrip terlebih dahulu dan memeriksanya sebelum menjalankan:

curl -fsSL https://bun.sh/install -o install.sh
# Periksa install.sh jika diinginkan
bash install.sh

Metode Instalasi Lainnya:

npm install -g bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun:latest bun --version
brew tap oven-sh/bun
brew install bun

Verifikasi:

Setelah terinstal, buka jendela terminal baru dan verifikasi instalasi dengan memeriksa versinya:

bun --version

Ini akan menampilkan nomor versi yang terinstal, mengonfirmasi bahwa Bun siap digunakan. Anda juga dapat menjalankan bun --help untuk melihat daftar perintah dan opsi yang tersedia.

Jalankan Bun Anda untuk Pertama Kali

Mari kita selami menulis dan menjalankan program sederhana dengan Bun. Salah satu tugas paling umum adalah membuat server HTTP. Bun menyediakan API bawaan yang sangat dioptimalkan untuk tujuan ini: Bun.serve.

Buat file baru bernama server.js (atau server.ts, karena Bun menangani keduanya):

// server.ts

// Bun.serve memulai server HTTP
const server = Bun.serve({
  // Tentukan port untuk didengarkan.
  // Default ke process.env.PORT || 3000
  port: 3000,

  // Fungsi 'fetch' adalah handler permintaan inti.
  // Ini menerima objek Request standar dan harus mengembalikan objek Response (atau Promise yang menyelesaikannya).
  fetch(request: Request): Response {
    // Buat objek Response API Web standar
    return new Response("Welcome to Bun!");
  },
});

// Log pesan yang menunjukkan server sedang berjalan
console.log(`Listening on http://localhost:${server.port}`);

Cuplikan kode ini melakukan hal berikut:

  1. Ini memanggil Bun.serve, fungsi utama untuk membuat server HTTP di Bun.
  2. Ini meneruskan objek konfigurasi, menentukan port (3000 dalam kasus ini).
  3. Bagian krusial adalah fungsi fetch. Fungsi ini dipanggil untuk setiap permintaan HTTP yang masuk. Ini selaras dengan pola handler peristiwa fetch Service Worker, menerima objek Request standar.
  4. Di dalam fetch, kita membangun dan mengembalikan objek Response standar. Di sini, kita hanya mengembalikan teks biasa "Welcome to Bun!".
  5. Terakhir, kita mencatat pesan konfirmasi ke konsol, termasuk port aktual yang didengarkan oleh server (dapat diakses melalui server.port).

Untuk menjalankan server ini, buka terminal Anda di direktori tempat Anda menyimpan file dan eksekusi:

bun run server.ts

Atau, jika Anda menyimpannya sebagai server.js:

bun run server.js

Bun akan mengeksekusi skrip. Jika Anda menggunakan TypeScript (server.ts), transpiler internal Bun akan menangani konversi ke JavaScript secara langsung sebelum eksekusi. Anda akan melihat pesan "Listening on http://localhost:3000".

Sekarang, buka browser web Anda dan navigasikan ke http://localhost:3000. Anda akan melihat teks "Welcome to Bun!" ditampilkan.

Untuk menghentikan server, kembali ke terminal Anda dan tekan Ctrl + C.

Contoh sederhana ini menunjukkan kemudahan menyiapkan server dasar dan menjalankan kode (termasuk TypeScript) langsung dengan Bun, menampilkan sifat terintegrasinya dan ketergantungan pada API Standar Web seperti Request dan Response.

Apa Dukungan Native TypeScript di Bun

Salah satu keunggulan paling signifikan dari Bun, terutama bagi pengembang yang sudah menggunakan atau ingin mengadopsi TypeScript, adalah dukungan kelas satu, siap pakainya. Berbeda dengan Node.js, di mana menjalankan TypeScript biasanya memerlukan pra-kompilasi menggunakan kompiler TypeScript (tsc) atau menggunakan loader/register seperti ts-node atau tsx, Bun menanganinya secara native dan transparan.

Cara Kerjanya:

Ketika Anda meminta Bun untuk menjalankan file .ts atau .tsx (misalnya, bun run myscript.ts), ia secara otomatis memanggil transpiler internalnya. Transpiler ini ditulis dalam kode native (Zig) dan sangat cepat. Tugasnya adalah:

  1. Menghapus Tipe: Menghapus anotasi tipe TypeScript, interface, enum, dll., karena ini bukan bagian dari eksekusi JavaScript standar.
  2. Mengubah Sintaks: Mengonversi sintaks spesifik TypeScript (seperti penggunaan enum tertentu atau sintaks dekorator yang lebih lama jika dikonfigurasi) menjadi JavaScript yang setara.
  3. Menangani JSX: Mengubah sintaks JSX (digunakan dalam file .tsx dan .jsx) menjadi panggilan fungsi JavaScript standar (biasanya React.createElement atau setara runtime JSX yang dikonfigurasi).

Manfaat utamanya adalah ini terjadi secara langsung selama proses eksekusi (bun run) atau bundling (bun build). Tidak ada langkah build terpisah dan eksplisit yang diperlukan hanya untuk menjalankan kode TypeScript Anda selama pengembangan.

Contoh:

Pertimbangkan file TypeScript ini (greet.ts):

// greet.ts
interface User {
  name: string;
  id: number;
}

function greetUser(user: User): void {
  console.log(`Hello, ${user.name} (ID: ${user.id})!`);
}

const myUser: User = { name: "Bun Developer", id: 123 };

greetUser(myUser);

// Anda bahkan dapat menggunakan fitur modern yang didukung Bun
const message = `Bun version: ${Bun.version}`;
console.log(message);

Anda dapat menjalankan ini secara langsung:

bun run greet.ts

Bun akan mentranspilasinya secara internal dan mengeksekusi JavaScript yang dihasilkan, menghasilkan output seperti:

Hello, Bun Developer (ID: 123)!
Bun version: 1.x.y

Dukungan JSX:

Demikian pula, jika Anda memiliki file .tsx dengan JSX:

// component.tsx

// Dengan asumsi Anda telah mengonfigurasi JSX (default Bun seringkali berfungsi dengan React)
function MyComponent({ name }: { name: string }) {
  return <div className="greeting">Hello, {name}!</div>;
}

// CATATAN: Menjalankan ini secara langsung tidak akan me-render HTML,
// ini hanya menunjukkan struktur JS yang ditranspilasi.
// Anda biasanya akan menggunakannya dalam aplikasi atau framework yang lebih besar.
console.log("Mensimulasikan pembuatan komponen (struktur output yang ditranspilasi):");
// Output aktual tergantung pada pengaturan transformasi JSX,
// tetapi itu akan menjadi objek/panggilan fungsi JavaScript.

Menjalankan bun run component.tsx akan mengeksekusi file, mentranspilasi JSX menjadi JavaScript.

Konfigurasi (tsconfig.json):

Bun menghormati file tsconfig.json untuk opsi konfigurasi yang memengaruhi transpilation. Meskipun tidak melakukan pemeriksaan tipe penuh seperti tsc (Bun berfokus pada kecepatan eksekusi dan transpilation), ia membaca tsconfig.json untuk memahami pengaturan seperti:

Jika tidak ada tsconfig.json yang ditemukan, Bun menggunakan pengaturan default yang masuk akal.

Integrasi mulus ini membuat memulai proyek TypeScript dengan Bun sangat sederhana dan cepat, menurunkan hambatan masuk dan mempercepat siklus pengembangan.

Mari Bicara Tentang API Spesifik Bun

Meskipun Bun sangat menekankan kompatibilitas dengan API Standar Web dan Node.js, ia juga memperkenalkan serangkaian API bawaannya sendiri yang dioptimalkan di bawah objek global Bun. API ini seringkali menyediakan alternatif berperforma tinggi atau pembungkus yang nyaman untuk tugas-tugas umum yang memanfaatkan kemampuan kode native Bun.

Berikut adalah sekilas beberapa API Bun.* utama:

API ini mewakili upaya Bun untuk menyediakan solusi bawaan yang dioptimalkan untuk tugas-tugas pengembangan umum, mengurangi ketergantungan pada dependensi eksternal dan memanfaatkan kecepatan inti native-nya.

API Web di Bun

Pilihan desain fundamental di Bun adalah komitmen kuatnya untuk mengimplementasikan API Web standar. Di mana pun API standar ada untuk tugas tertentu (terutama untuk penanganan jaringan dan data), Bun lebih memilih untuk mengimplementasikan standar tersebut daripada menciptakan API proprietary atau hanya mengandalkan konvensi Node.js.

Pendekatan ini menawarkan beberapa keuntungan signifikan:

  1. Portabilitas Kode: Kode yang ditulis menggunakan API Web standar seringkali dapat digunakan kembali di berbagai lingkungan JavaScript – browser, Node.js (yang juga semakin mengadopsi standar Web), Deno, Cloudflare Workers, dan Bun – dengan lebih sedikit modifikasi.
  2. Keterbiasaan: Pengembang yang sudah familiar dengan API browser dapat memanfaatkan pengetahuan tersebut saat bekerja dengan Bun, mengurangi kurva pembelajaran.
  3. Tahan Masa Depan: Penyelarasan dengan standar yang ditetapkan oleh badan seperti WHATWG dan W3C umumnya mengarah pada API yang lebih stabil dan didukung secara luas dalam jangka panjang.
  4. Kinerja: Implementasi native Bun dari API Web ini sangat dioptimalkan untuk runtime-nya.

API Standar Web utama yang diimplementasikan di Bun meliputi:

Fetch API:

URL API:

Streams API:

Encoding API:

Blob API:

FormData API:

WebSocket API:

Timers:

Console API:

Crypto API:

Performance API:

Dengan menyediakan implementasi yang kuat dan berperforma dari API Web penting ini, Bun memposisikan dirinya sebagai runtime modern yang cocok untuk membangun server web, API, dan aplikasi berpusat jaringan lainnya menggunakan antarmuka standar yang familiar.

Server HTTP Bun, Dijelaskan

Cara utama untuk membuat server web di Bun adalah melalui API Bun.serve. Ini dirancang untuk kinerja luar biasa dan kemudahan penggunaan, berintegrasi secara mulus dengan API Web standar seperti Request, Response, dan fetch.

Konsep Inti:

Fungsi Bun.serve mengambil objek konfigurasi dan mengembalikan objek Server. Bagian terpenting dari konfigurasi adalah fungsi fetch.

import { type Server } from "bun";

const server: Server = Bun.serve({
  port: 8080, // Port untuk didengarkan
  hostname: "0.0.0.0", // Antarmuka jaringan untuk diikat (0.0.0.0 untuk semua)

  // fetch: Jantung server - menangani permintaan masuk
  async fetch(req: Request, server: Server): Promise<Response> {
    // req adalah objek Request API Web standar
    // server adalah referensi ke instance Server itu sendiri

    const url = new URL(req.url);

    // Contoh Routing Dasar
    if (url.pathname === "/") {
      return new Response("Homepage");
    }
    if (url.pathname === "/about") {
      return new Response("About Us page");
    }
    if (url.pathname === "/greet" && req.method === "GET") {
        const name = url.searchParams.get("name") || "World";
        return new Response(`Hello, ${name}!`);
    }
     if (url.pathname === "/data" && req.method === "POST") {
        try {
            const data = await req.json(); // Baca body permintaan sebagai JSON
            console.log("Received data:", data);
            return new Response(JSON.stringify({ received: data }), {
               headers: { 'Content-Type': 'application/json' }
            });
        } catch (e) {
            return new Response("Invalid JSON body", { status: 400 });
        }
    }

    // Default 404 Not Found
    return new Response("Page Not Found", { status: 404 });
  },

  // error: Handler opsional untuk kesalahan yang terjadi *di luar* handler fetch
  error(error: Error): Response | Promise<Response> {
    console.error("[Server Error]", error);
    return new Response("Something went wrong!", { status: 500 });
  },

  // development: Setel ke true untuk halaman kesalahan pengembangan yang membantu (default: !process.env.NODE_ENV=production)
   development: true,

   // Opsi lain seperti 'websocket', 'tls' ada untuk kasus penggunaan lanjutan
});

console.log(`Bun server listening on http://${server.hostname}:${server.port}`);

// Anda dapat berinteraksi dengan objek server:
// server.stop() // Menghentikan server
// server.reload({...}) // Memperbarui konfigurasi server (misalnya, handler fetch) secara dinamis

Fitur Utama:

Bun.serve menyediakan dasar yang kuat namun sederhana untuk membangun aplikasi web dan API di Bun, memprioritaskan kecepatan dan kepatuhan terhadap standar web.

Klien Bun Fetch

Melengkapi API server, Bun menyediakan fungsi fetch global untuk membuat permintaan HTTP(S) keluar. Implementasi ini sangat mematuhi standar WHATWG Fetch, membuatnya familiar bagi pengembang web dan memastikan konsistensi dengan fungsi fetch yang digunakan dalam Bun.serve. Implementasi native Bun memastikan kinerja tinggi untuk tugas jaringan sisi klien.

Membuat Permintaan:

Penggunaan dasar melibatkan pemanggilan fetch dengan URL dan secara opsional objek konfigurasi:

async function makeRequests() {
  const url = "https://httpbin.org"; // Layanan yang berguna untuk menguji permintaan HTTP

  // --- Permintaan GET Dasar ---
  console.log("--- Permintaan GET ---");
  try {
    const getResponse = await fetch(`${url}/get?param1=value1`);

    console.log(`Status: ${getResponse.status} ${getResponse.statusText}`);

    // Periksa apakah permintaan berhasil (status 200-299)
    if (!getResponse.ok) {
      throw new Error(`Kesalahan HTTP! status: ${getResponse.status}`);
    }

    // Akses header
    console.log("Header Content-Type:", getResponse.headers.get('content-type'));

    // Baca body respons sebagai JSON
    const getData = await getResponse.json();
    console.log("JSON Respons:", getData.args); // httpbin.org/get mengembalikan parameter query di 'args'

  } catch (error) {
    console.error("Permintaan GET gagal:", error);
  }

  // --- Permintaan POST dengan body JSON ---
  console.log("\n--- Permintaan POST (JSON) ---");
  try {
     const postData = { name: "Bun", type: "Runtime" };
     const postResponse = await fetch(`${url}/post`, {
        method: "POST",
        headers: {
          // Menunjukkan kita mengirim JSON
          "Content-Type": "application/json",
          "Accept": "application/json", // Menunjukkan kita lebih suka JSON kembali
          "X-Custom-Header": "BunFetchExample",
        },
        // Body harus di-stringifikasi untuk JSON
        body: JSON.stringify(postData),
     });

     if (!postResponse.ok) {
        throw new Error(`Kesalahan HTTP! status: ${postResponse.status}`);
     }

     const postResult = await postResponse.json();
     console.log("JSON Respons POST:", postResult.json); // httpbin.org/post mengembalikan JSON yang diposting di 'json'

  } catch (error) {
     console.error("Permintaan POST gagal:", error);
  }

   // --- Permintaan dengan Timeout ---
   console.log("\n--- Permintaan GET dengan Timeout ---");
   try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 2000); // Batalkan setelah 2 detik

      const timeoutResponse = await fetch(`${url}/delay/5`, { // Endpoint ini menunggu 5 detik
         signal: controller.signal // Teruskan AbortSignal
      });

      clearTimeout(timeoutId); // Hapus timeout jika fetch selesai lebih cepat
      console.log("Permintaan timeout berhasil (tidak terduga untuk /delay/5)");

   } catch (error: any) {
      // AbortError dilemparkan saat sinyal membatalkan
      if (error.name === 'AbortError') {
         console.log("Fetch dibatalkan karena timeout, seperti yang diharapkan.");
      } else {
         console.error("Permintaan timeout gagal:", error);
      }
   }
}

await makeRequests();

Fitur dan Opsi Utama:

API Standar: Menggunakan tanda tangan fetch(url, options) yang familiar.

Metode: Mendukung semua metode HTTP standar (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS). Ditentukan melalui opsi method.

Header: Header diatur menggunakan opsi headers, yang dapat berupa objek Headers atau objek biasa key-value sederhana.

Body Permintaan: Opsi body menerima berbagai tipe:

Penanganan Respons: Panggilan fetch mengembalikan Promise yang menyelesaikan ke objek Response.

Timeout & Pembatalan: Gunakan AbortController dan AbortSignal untuk mengimplementasikan timeout atau membatalkan permintaan secara manual. Teruskan signal ke opsi fetch.

Pengalihan: Dikontrol oleh opsi redirect ('follow', 'manual', 'error'). Default ke 'follow'.

fetch Bun menyediakan cara yang berperforma dan sesuai standar untuk berinteraksi dengan sumber daya HTTP, berintegrasi secara mulus ke dalam ekosistem Bun.

WebSocket Bun

WebSocket menyediakan cara untuk membangun saluran komunikasi persisten, dua arah antara klien dan server melalui satu koneksi TCP. Bun menawarkan dukungan luar biasa untuk WebSocket, baik untuk membuat klien WebSocket maupun untuk menangani koneksi WebSocket di sisi server dalam Bun.serve.

1. Klien WebSocket:

Bun mengimplementasikan API WebSocket browser standar untuk membuat koneksi klien.

// websocket-client.ts

const wsUrl = "wss://ws.postman-echo.com/raw"; // Server echo publik

console.log(`Menghubungkan klien ke ${wsUrl}...`);

const socket = new WebSocket(wsUrl);

// Event: Koneksi berhasil dibuka
socket.addEventListener("open", (event) => {
  console.log("[Klien] Koneksi WebSocket berhasil dibuat!");
  socket.send("Halo dari klien Bun!");

  // Kirim data biner setelah jeda singkat
  setTimeout(() => {
     const binaryData = new TextEncoder().encode("Data biner Bun");
     console.log("[Klien] Mengirim biner:", binaryData);
     socket.send(binaryData);
  }, 500);

   // Tutup koneksi setelah beberapa waktu
  setTimeout(() => {
     console.log("[Klien] Menutup koneksi...");
     socket.close(1000, "Klien selesai menguji"); // 1000 = Penutupan normal
  }, 2000);
});

// Event: Pesan diterima dari server
socket.addEventListener("message", async (event) => {
  // event.data bisa berupa string, Blob, atau ArrayBuffer
  let messageContent: string | Uint8Array;
  if (typeof event.data === "string") {
    messageContent = event.data;
    console.log(`[Klien] Menerima string: "${messageContent}"`);
  } else if (event.data instanceof Blob) {
    // Bun sering menerima data biner sebagai Blob dari API WebSocket
    const arrayBuffer = await event.data.arrayBuffer();
    messageContent = new Uint8Array(arrayBuffer);
    console.log(`[Klien] Menerima biner (Blob):`, messageContent, `(${new TextDecoder().decode(messageContent)})`);
  } else if (event.data instanceof ArrayBuffer) {
     messageContent = new Uint8Array(event.data);
     console.log(`[Klien] Menerima biner (ArrayBuffer):`, messageContent, `(${new TextDecoder().decode(messageContent)})`);
  } else {
    console.log("[Klien] Menerima tipe pesan tidak dikenal:", event.data);
  }
});

// Event: Terjadi kesalahan (masalah jaringan, dll.)
socket.addEventListener("error", (event) => {
  // Objek event seringkali kurang detail spesifik. Periksa log konsol/jaringan.
  console.error("[Klien] Kesalahan WebSocket:", event.type);
});

// Event: Koneksi ditutup
socket.addEventListener("close", (event) => {
  console.log(
    `[Klien] WebSocket ditutup. Kode: ${event.code}, Alasan: "${event.reason}", Bersih: ${event.wasClean}`
  );
  // Keluar dari skrip dengan bersih setelah socket ditutup
  process.exit(0);
});

// Tetap hidup sebentar untuk event, keluar ditangani di listener 'close'
// setInterval(() => {}, 1000);

Jalankan ini dengan bun run websocket-client.ts. Ini terhubung ke server echo, mengirim pesan, menerimanya kembali, lalu menutup.

2. Server WebSocket (Integrasi Bun.serve):

Menangani koneksi WebSocket di server dilakukan dengan menambahkan properti websocket ke objek konfigurasi Bun.serve. Properti ini berisi fungsi handler untuk berbagai peristiwa siklus hidup WebSocket.

// websocket-server.ts
import { type ServerWebSocket, type WebSocketHandler } from "bun";

console.log("Memulai server WebSocket...");

// Definisikan objek handler WebSocket
const wsHandler: WebSocketHandler<{ authToken: string }> = {
  // open(ws): Dipanggil saat koneksi WebSocket baru dibuat.
  // Panggilan server.upgrade() di 'fetch' diperlukan terlebih dahulu.
  open(ws: ServerWebSocket<{ authToken: string }>) {
    console.log(`[Server] Koneksi dibuka. Token: ${ws.data.authToken}`);
    ws.send("Selamat datang di server WebSocket Bun!");
    // Berlangganan topik pub/sub
    ws.subscribe("the-group-chat");
    // Publikasikan pesan ke topik (termasuk pengguna baru)
    ws.publish("the-group-chat", `Pengguna dengan token ${ws.data.authToken} bergabung.`);
  },

  // message(ws, message): Dipanggil saat pesan diterima dari klien.
  // 'message' bisa berupa string atau Uint8Array (Buffer).
  message(ws: ServerWebSocket<{ authToken: string }>, message: string | Buffer) {
    const messageString = message.toString(); // Tangani string/buffer
    console.log(`[Server] Menerima dari token ${ws.data.authToken}: ${messageString}`);

     // Echo kembali pesan yang diawali dengan token
    // ws.send(`[${ws.data.authToken}] Anda mengirim: ${messageString}`);

    // Publikasikan pesan ke semua orang di ruang obrolan (termasuk pengirim)
    server.publish("the-group-chat", `[${ws.data.authToken}] ${messageString}`);
  },

  // close(ws, code, reason): Dipanggil saat koneksi WebSocket ditutup.
  close(ws: ServerWebSocket<{ authToken: string }>, code: number, reason: string) {
    const goodbyeMessage = `[Server] Koneksi ditutup. Token: ${ws.data.authToken}, Kode: ${code}, Alasan: ${reason}`;
    console.log(goodbyeMessage);
     // Berhenti berlangganan dan beri tahu yang lain
     ws.unsubscribe("the-group-chat");
     server.publish("the-group-chat", `Pengguna dengan token ${ws.data.authToken} keluar.`);
  },

  // drain(ws): Opsional. Dipanggil saat jumlah buffer socket berkurang,
  // menunjukkan bahwa ia siap menerima lebih banyak data setelah backpressure.
  // Berguna untuk mengelola kontrol aliran saat mengirim data dalam jumlah besar.
  // drain(ws: ServerWebSocket<{ authToken: string }>) {
  //   console.log(`[Server] Peristiwa drain untuk token ${ws.data.authToken}`);
  // },
};

// Buat server HTTP dengan penanganan WebSocket
const server = Bun.serve<{ authToken: string }>({ // Teruskan generik untuk tipe ws.data
  port: 8081,

  // Handler fetch perlu menangani permintaan upgrade HTTP -> WebSocket
  fetch(req: Request, server: Server): Response | undefined {
    const url = new URL(req.url);
    // Periksa apakah permintaan mencoba melakukan upgrade ke WebSocket
    if (url.pathname === "/ws") {
       // Ekstrak beberapa data (misalnya, token auth) untuk diteruskan ke konteks WebSocket
       const token = req.headers.get("sec-websocket-protocol") || "anonymous"; // Contoh: gunakan header protokol untuk token
       const success = server.upgrade(req, {
         // Objek data dilampirkan ke instance ws (ws.data)
         // tersedia di semua handler websocket untuk koneksi ini.
         // HARUS dapat diserialisasi JSON jika menggunakan di seluruh worker/proses nanti.
         data: {
           authToken: token,
         },
         // headers: new Headers({ 'X-Custom-Response-Header': 'UpgradeValue' }) // Opsional: Tambahkan header ke respons 101
      });

      if (success) {
        // server.upgrade() menangani respons 101 Switching Protocols.
        // Kembalikan undefined dari handler fetch setelah upgrade berhasil.
        return undefined;
      } else {
         // Upgrade gagal (misalnya, header permintaan tidak valid)
         return new Response("Upgrade WebSocket gagal", { status: 400 });
      }
    }

    // Tangani permintaan HTTP biasa di jalur lain
    return new Response("Bukan endpoint WebSocket. Coba /ws", { status: 404 });
  },

  // Lampirkan objek handler WebSocket
  websocket: wsHandler,

  error(error: Error): Response | Promise<Response> {
    console.error("[Server Error]", error);
    return new Response("Kesalahan server", { status: 500 });
  },
});

console.log(`Server WebSocket Bun mendengarkan di ws://localhost:${server.port}/ws`);

Konsep Utama Server:

Permintaan Upgrade: Koneksi WebSocket dimulai sebagai permintaan GET HTTP standar dengan header spesifik (Upgrade: websocket, Connection: Upgrade, Sec-WebSocket-Key, dll.). Handler fetch harus mendeteksi permintaan ini.

Pub/Sub: Bun menyertakan kemampuan publish/subscribe bawaan yang efisien untuk WebSocket:

Backpressure: Metode ws.send() mengembalikan jumlah byte yang di-buffer. Jika nilai ini bertambah besar, Anda mungkin mengirim lebih cepat daripada yang dapat diterima klien. Peristiwa drain memberi sinyal saat buffer telah menyusut, memungkinkan Anda melanjutkan pengiriman dengan aman.

Dukungan WebSocket terintegrasi Bun menyediakan cara yang berperforma dan nyaman untuk membangun fitur real-time ke dalam aplikasi, lengkap dengan fungsionalitas pub/sub bawaan.


Panduan ini telah membahas aspek fundamental Bun, mulai dari filosofi inti dan instalasinya hingga API spesifiknya seperti Bun.serve, Bun.file, Bun.build, dan implementasinya dari Standar Web krusial seperti fetch dan WebSocket. Dengan menggabungkan kecepatan, alat terintegrasi, dukungan TypeScript/JSX native, dan fokus pada standar, Bun menawarkan lingkungan yang menarik dan produktif untuk pengembangan JavaScript dan TypeScript modern.

💡
Ingin alat Pengujian API hebat yang menghasilkan Dokumentasi API yang indah?

Ingin platform All-in-One yang terintegrasi untuk Tim Pengembang Anda bekerja sama dengan produktivitas maksimum?

Apidog memenuhi semua permintaan Anda, dan menggantikan Postman dengan harga yang jauh lebih terjangkau!
button

Mengembangkan API dengan Apidog

Apidog adalah alat pengembangan API yang membantu Anda mengembangkan API dengan lebih mudah dan efisien.