التوثيق الشامل لمنصة Bun.js

دليل مفصل لجميع ميزات وواجهات برمجة التطبيقات في Bun.js

مقدمة عن Bun.js

Bun.js هو بيئة تشغيل JavaScript و TypeScript حديثة تركز على ثلاثة أهداف رئيسية:

  • السرعة: تم تصميم Bun.js ليكون أسرع بكثير من Node.js، حيث يستخدم محرك JavaScriptCore (من Safari) بدلاً من محرك V8 (من Chrome).
  • الأدوات الموحدة: يجمع Bun.js بين بيئة التشغيل ومدير الحزم ومجمع الشيفرة والاختبارات في أداة واحدة.
  • التوافقية: متوافق مع النظام البيئي الحالي لـ Node.js و npm، مما يجعل الانتقال إليه سهلاً.

لماذا Bun.js؟

إليك بعض الأسباب الرئيسية التي تجعل المطورين يختارون Bun.js:

الأداء العالي

يبدأ Bun.js بسرعة فائقة ويستهلك موارد أقل من Node.js مما يجعله مثالياً للتطبيقات التي تحتاج إلى وقت استجابة سريع.

الاستخدام السهل

واجهة بسيطة وموحدة لجميع مهام التطوير، من تشغيل الشيفرة إلى بناء التطبيقات وإدارة الحزم واختبارها.

التوافق المدمج

دعم مدمج لـ TypeScript وJSX وملفات .env والوحدات (ES modules و CommonJS) والحزم الخارجية.

نموذج API حديث

يستخدم واجهات برمجة حديثة مثل Fetch API وWeb Streams وAPI مبسطة للملفات والشبكة.

تثبيت Bun.js

توفر Bun.js طرقاً متعددة للتثبيت على أنظمة التشغيل المختلفة. فيما يلي الطرق الرئيسية لتثبيت Bun.js بالتفصيل:

تثبيت سريع على macOS و Linux

أسرع طريقة لتثبيت Bun.js على أنظمة macOS وLinux هي استخدام سكربت التثبيت الرسمي:

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

هذا الأمر يقوم بتنزيل سكربت التثبيت وتنفيذه على جهازك. السكربت سيقوم بتحميل الإصدار المناسب لنظام التشغيل والمعمارية الخاصة بك وتثبيته في المسار المناسب.

تثبيت باستخدام Homebrew على macOS

إذا كنت تستخدم مدير الحزم Homebrew على نظام macOS، يمكنك استخدام الأوامر التالية:

# إضافة مستودع Bun إلى Homebrew
brew tap oven-sh/bun

# تثبيت Bun
brew install bun

يعتبر هذا الخيار مفضلاً للمستخدمين الذين يعتمدون على Homebrew لإدارة البرمجيات على أنظمتهم.

تثبيت باستخدام Docker

إذا كنت تفضل استخدام حاويات Docker، يمكنك استخدام الصورة الرسمية لـ Bun.js:

# سحب الصورة الرسمية
docker pull oven/bun

# تشغيل حاوية Bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

الخيارات المستخدمة:

  • --rm: حذف الحاوية بعد الخروج منها
  • --init: استخدام عملية تهيئة داخل الحاوية
  • --ulimit memlock=-1:-1: إزالة حدود الذاكرة لتحسين الأداء

تثبيت على Windows باستخدام WSL

لاستخدام Bun.js على نظام Windows، ستحتاج إلى تثبيت WSL2 (Windows Subsystem for Linux) أولاً:

# تثبيت WSL2 من PowerShell (بصلاحيات المسؤول)
wsl --install

بعد تثبيت WSL2 وإعداد توزيعة Linux (مثل Ubuntu)، يمكنك تثبيت Bun.js داخل بيئة WSL:

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

تثبيت إصدار محدد

إذا كنت بحاجة إلى تثبيت إصدار محدد من Bun.js، يمكنك تحديده عبر متغير بيئي:

curl -fsSL https://bun.sh/install | BUN_INSTALL_VERSION="0.5.9" bash

التحقق من التثبيت

بعد الانتهاء من التثبيت، يمكنك التحقق من نجاح العملية ومعرفة الإصدار المثبت:

# التحقق من الإصدار المثبت
bun --version

# عرض معلومات النظام والبيئة
bun --info

سيعرض لك الأمر الثاني معلومات مفصلة عن نظامك وبيئة Bun.js المثبتة.

ملاحظة مهمة

يتم تطوير Bun.js بشكل مستمر وإطلاق تحديثات متكررة. يُنصح دائماً بالتحديث إلى أحدث إصدار للحصول على أفضل أداء وجميع الميزات والإصلاحات الأمنية. يمكن تحديث Bun.js باستخدام الأمر:

bun upgrade

بيئة تشغيل Bun.js

تعتبر Bun.js بيئة تشغيل JavaScript و TypeScript كاملة، مصممة لتكون بديلاً أسرع وأكثر كفاءة من Node.js. تستخدم محرك JavaScriptCore (من Safari) بدلاً من V8 (من Chrome) مما يوفر بدء تشغيل أسرع وأداء أفضل في معظم الحالات.

أساسيات تشغيل الملفات

يمكن استخدام Bun.js لتشغيل ملفات JavaScript وTypeScript وJSX مباشرة دون الحاجة إلى خطوات تجميع مسبقة:

تشغيل ملف JavaScript

لتشغيل ملف JavaScript، استخدم الأمر التالي:

bun run hello.js

مثال لمحتوى ملف JavaScript بسيط (hello.js):

// hello.js
console.log("Hello from Bun.js!");

// استخدام وظائف غير متزامنة 
async function fetchData() {
  const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
  const data = await response.json();
  console.log("Fetched data:", data);
}

fetchData();

تشغيل ملف TypeScript

يمكن تشغيل ملفات TypeScript مباشرة دون الحاجة لتحويلها أولاً:

bun run hello.ts

مثال لمحتوى ملف TypeScript (hello.ts):

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

async function getUser(id: number): Promise {
  const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  return await response.json();
}

async function main() {
  try {
    const user = await getUser(1);
    console.log(`User: ${user.name} (${user.email})`);
  } catch (error) {
    console.error("Error fetching user:", error);
  }
}

main();

الأمر المختصر

يمكن استخدام bun مباشرة بدلاً من bun run كاختصار لتشغيل الملفات:

bun hello.js
bun hello.ts

الميزات الأساسية لبيئة التشغيل

استيراد الوحدات (Modules)

يدعم Bun.js كلاً من ES Modules وCommonJS:

// استيراد بصيغة ES Modules
import fs from 'fs';
import { readFile } from 'fs/promises';

// استيراد بصيغة CommonJS (يدعم أيضاً)
const path = require('path');

وحدات مدمجة خاصة ببن

يوفر Bun.js وحدات مدمجة خاصة به يمكن استيرادها باستخدام بادئة bun::

// استيراد وحدة الاختبار المدمجة
import { test, expect } from 'bun:test';

// استيراد وحدة الملفات الثنائية
import { BinaryData } from 'bun:binary';

وضع المراقبة (Watch Mode)

يمكن تشغيل الملفات في وضع المراقبة، حيث يعيد Bun.js تشغيل التطبيق تلقائياً عند تغيير الملفات:

bun --watch index.ts

استخدام واجهات برمجة الويب القياسية

يوفر Bun.js دعماً لواجهات برمجة الويب القياسية مثل Fetch و Request و Response و Headers و URL وغيرها:

// استخدام Fetch API
const response = await fetch('https://example.com/api');
const data = await response.json();

// استخدام URL API
const url = new URL('https://example.com/search');
url.searchParams.set('q', 'bun js');
console.log(url.toString()); // https://example.com/search?q=bun%20js

// استخدام Headers API
const headers = new Headers();
headers.set('Content-Type', 'application/json');
headers.set('Authorization', 'Bearer token123');

الوصول إلى متغيرات البيئة

يمكن الوصول إلى متغيرات البيئة عبر process.env أو Bun.env:

// استخدام متغيرات البيئة
console.log(process.env.NODE_ENV); // متوافق مع Node.js
console.log(Bun.env.NODE_ENV);     // وصول مباشر من كائن Bun

إنشاء مشروع جديد

يوفر Bun.js أمراً لإنشاء مشاريع جديدة باستخدام قوالب متعددة:

# إنشاء مشروع باستخدام القالب الافتراضي
bun create empty-project my-project

# إنشاء مشروع React
bun create react my-react-app

# إنشاء مشروع Next.js
bun create next my-next-app

# إنشاء مشروع React مع TypeScript
bun create react-ts my-react-ts-app

المجمّع (Bundler)

يتضمن Bun.js مجمّعاً (bundler) مدمجاً يمكن استخدامه لتجميع وحزم ملفات JavaScript وTypeScript:

التجميع الأساسي

لتجميع ملف وجميع وحداته:

# تجميع ملف index.ts وإخراج النتيجة في مجلد dist
bun build ./index.ts --outdir ./dist

تصغير الكود

يمكن تصغير الكود الناتج لتحسين الأداء وتقليل الحجم:

# تجميع مع تصغير
bun build ./index.ts --outdir ./dist --minify

تحويل إلى منصات محددة

يمكن تحديد المنصة المستهدفة للكود الناتج:

# تحويل إلى كود مناسب للمتصفح
bun build ./index.ts --outdir ./dist --target browser

# تحويل إلى كود مناسب للتشغيل في بيئة Node.js
bun build ./index.ts --outdir ./dist --target node

إنشاء حزمة قابلة للتنفيذ

يمكن إنشاء ملف تنفيذي مستقل من الكود المصدري:

# إنشاء ملف تنفيذي
bun build ./cli.ts --compile --outfile mycli

تكوين الحزم (Bundling Configuration)

يمكن تحديد خيارات التجميع المتقدمة باستخدام ملف تكوين:

// bunfig.toml
[bundle]
entrypoints = ["./src/index.ts"]
outdir = "./dist"
minify = true
target = "browser"
format = "esm"
sourcemap = "external"

ثم تنفيذ التجميع باستخدام التكوين المحدد:

bun build

خادم HTTP في Bun.js

توفر Bun.js واجهة برمجة مبسطة وعالية الأداء لإنشاء خوادم HTTP. تم تصميم واجهة البرمجة هذه لتكون سهلة الاستخدام مع الحفاظ على الأداء العالي.

إنشاء خادم HTTP بسيط

لإنشاء خادم HTTP بسيط في Bun.js، يمكنك استخدام دالة serve المدمجة:

// server.js - خادم بسيط
import { serve } from "bun";

const server = serve({
port: 3000, // المنفذ الافتراضي هو 3000
fetch(req) {
return new Response("مرحباً بالعالم من Bun.js!");
},
});

console.log(`الخادم يعمل الآن على المنفذ ${server.port}`);

يمكن تشغيل هذا الخادم باستخدام:

bun run server.js

معالجة الطلبات

تتبع واجهة برمجة التطبيقات معيار Fetch API، مما يعني أنك تتعامل مع كائنات Request و Response القياسية:

// التعامل مع طرق الطلب المختلفة والمسارات
const server = serve({
fetch(req) {
const url = new URL(req.url);
const method = req.method;

// معالجة المسارات المختلفة
if (url.pathname === "/") {
return new Response("الصفحة الرئيسية");
}

if (url.pathname === "/api/users" && method === "GET") {
// إرجاع بيانات بتنسيق JSON
return Response.json({
users: [
{ id: 1, name: "أحمد" },
{ id: 2, name: "سارة" },
{ id: 3, name: "محمد" }
]
});
}

if (url.pathname === "/api/users" && method === "POST") {
// يمكن معالجة البيانات المرسلة من النموذج
return new Response("تم إنشاء المستخدم بنجاح", { status: 201 });
}

// إرجاع استجابة 404 لأي مسار غير معروف
return new Response("الصفحة غير موجودة", { status: 404 });
}
});

استخراج بيانات الطلب

يمكن استخراج البيانات من طلبات POST وPUT بطرق متعددة:

// استخراج بيانات من طلب POST
if (url.pathname === "/api/submit" && method === "POST") {
// قراءة بيانات JSON
const jsonData = await req.json();
console.log("بيانات JSON:", jsonData);

// أو قراءة نص عادي
// const text = await req.text();

// أو قراءة بيانات النموذج
// const formData = await req.formData();
// const username = formData.get("username");

// أو قراءة بيانات ثنائية
// const buffer = await req.arrayBuffer();

return Response.json({ success: true });
}

إرسال ملفات

يمكن إرسال ملفات بسهولة باستخدام كائن Bun.file:

// إرسال ملف
if (url.pathname === "/download") {
const file = Bun.file("./files/document.pdf");
return new Response(file, {
headers: {
"Content-Type": "application/pdf",
"Content-Disposition": "attachment; filename=document.pdf"
}
});
}

// إرسال صورة
if (url.pathname === "/image.jpg") {
const image = Bun.file("./images/photo.jpg");
return new Response(image, {
headers: { "Content-Type": "image/jpeg" }
});
}

// إرسال صفحة HTML
if (url.pathname === "/page") {
const html = Bun.file("./public/page.html");
return new Response(html, {
headers: { "Content-Type": "text/html" }
});
}

دعم WebSockets

توفر Bun.js دعماً مدمجاً لبروتوكول WebSockets، مما يتيح إنشاء تطبيقات تفاعلية في الوقت الحقيقي:

// مثال لخادم WebSocket
import { serve } from "bun";

const server = serve({
fetch(req, server) {
// التحقق من أن الطلب هو طلب ترقية WebSocket
if (req.headers.get("Upgrade") === "websocket") {
// محاولة ترقية الاتصال
const success = server.upgrade(req);
if (success) {
// تمت الترقية بنجاح، لا حاجة لإرجاع استجابة HTTP
return;
}
return new Response("فشلت ترقية WebSocket", { status: 400 });
}

return new Response("هذا خادم WebSocket، استخدم بروتوكول WebSocket للاتصال.");
},
// معالجة أحداث WebSocket
websocket: {
// عندما يتم فتح اتصال جديد
open(ws) {
console.log("اتصال جديد!");
ws.send("مرحباً بك في خادم WebSocket!");
},
// عندما تصل رسالة من العميل
message(ws, message) {
console.log(`استلام رسالة: ${message}`);

// إعادة إرسال الرسالة إلى العميل
ws.send(`استلمت رسالتك: ${message}`);

// يمكن إرسال الرسالة لجميع العملاء المتصلين
// server.publish("channel", `رسالة جديدة: ${message}`);
},
// عندما يتم إغلاق الاتصال
close(ws, code, reason) {
console.log(`تم إغلاق الاتصال: ${code} ${reason}`);
}
}
});

console.log(`خادم WebSocket يعمل على المنفذ ${server.port}`);

مثال لعميل WebSocket (في المتصفح)

// كود العميل في JavaScript
const socket = new WebSocket("ws://localhost:3000");

// عند فتح الاتصال
socket.onopen = () => {
console.log("تم الاتصال بالخادم");
socket.send("مرحباً من العميل!");
};

// عند استلام رسالة
socket.onmessage = (event) => {
console.log("رسالة من الخادم:", event.data);
};

// عند إغلاق الاتصال
socket.onclose = () => {
console.log("تم إغلاق الاتصال");
};

// عند حدوث خطأ
socket.onerror = (error) => {
console.error("خطأ في الاتصال:", error);
};

إدارة الحزم في Bun.js

يأتي Bun.js مع مدير حزم مدمج سريع ومتوافق مع النظام البيئي لـ npm. يمكنه تثبيت الحزم من سجل npm وغيره من المصادر بسرعة عالية.

تثبيت الحزم

لتثبيت حزمة جديدة في مشروعك:

# تثبيت حزمة
bun install express

# تثبيت حزمة كاعتماد تطوير
bun install --dev typescript
# أو بشكل مختصر
bun install -d typescript

# تثبيت حزم متعددة
bun install react react-dom next

يمكن استخدام الأمر المختصر bun add بنفس الطريقة:

# تثبيت حزمة (مختصر)
bun add express

# تثبيت كاعتماد تطوير (مختصر)
bun add -d typescript

تحديث الحزم

لتحديث الحزم المثبتة:

# تحديث جميع الحزم
bun update

# تحديث حزمة محددة
bun update express

إزالة الحزم

لإزالة حزمة من المشروع:

# إزالة حزمة
bun remove express

سكربتات التشغيل

يمكن تعريف سكربتات في ملف package.json وتشغيلها باستخدام bun run:

{
"name": "my-project",
"version": "1.0.0",
"scripts": {
"dev": "bun run --watch src/index.ts",
"start": "bun run src/index.ts",
"build": "bun build src/index.ts --outdir dist",
"test": "bun test"
}
}

لتشغيل السكربتات:

# تشغيل سكربت dev
bun run dev

# تشغيل سكربت start
bun run start

تشغيل الحزم مباشرة

يمكن تشغيل الحزم مباشرة دون تثبيتها باستخدام الأمر bun x:

# تشغيل eslint مباشرة دون تثبيته محلياً
bun x eslint src/

# تشغيل أداة أخرى
bun x cowsay "مرحباً بالعالم"

ملف القفل (Lockfile)

يستخدم Bun.js ملف bun.lockb لتتبع إصدارات الحزم المثبتة. هذا الملف بتنسيق ثنائي مما يجعله أسرع وأكثر كفاءة من ملفات القفل النصية.

سرعة التثبيت

يعتبر مدير الحزم في Bun.js أسرع بكثير من npm أو yarn، حيث يمكنه تثبيت مئات الحزم في ثوانٍ قليلة. هذا يرجع إلى آلية تحميل موازية وتحسينات في تحليل وتخزين الحزم.

التعامل مع نظام الملفات

توفر Bun.js مجموعة من الواجهات البرمجية للتعامل مع نظام الملفات. تشمل واجهات متوافقة مع Node.js وواجهات خاصة ببن لتحسين الأداء.

قراءة الملفات

يوفر Bun.js طرقاً سريعة لقراءة الملفات:

// قراءة ملف باستخدام Bun.file
const file = Bun.file("path/to/file.txt");

// قراءة كنص
const text = await file.text();
console.log(text);

// قراءة كبيانات JSON
const jsonFile = Bun.file("path/to/config.json");
const config = await jsonFile.json();
console.log(config.name);

// قراءة كبيانات ثنائية
const binaryFile = Bun.file("path/to/image.png");
const data = await binaryFile.arrayBuffer();

// قراءة كـ Blob
const blob = await file.blob();

كتابة الملفات

يتيح Bun.js كتابة الملفات بشكل مبسط:

// كتابة نص إلى ملف
await Bun.write("path/to/file.txt", "محتوى الملف");

// كتابة بيانات JSON
const data = { name: "Ahmed", age: 30 };
await Bun.write("path/to/data.json", JSON.stringify(data, null, 2));

// كتابة بيانات ثنائية
const buffer = new Uint8Array([0, 1, 2, 3, 4]);
await Bun.write("path/to/binary.dat", buffer);

// كتابة من Blob أو Response
const response = await fetch("https://example.com/image.jpg");
const blob = await response.blob();
await Bun.write("image.jpg", blob);

التحقق من وجود الملفات

للتحقق من وجود ملف:

// التحقق من وجود ملف
const file = Bun.file("path/to/file.txt");
const exists = await file.exists();

if (exists) {
console.log("الملف موجود");
} else {
console.log("الملف غير موجود");
}

العمليات على المجلدات

للتعامل مع المجلدات، يمكن استخدام واجهات متوافقة مع Node.js:

// استيراد وحدات النظام المتوافقة مع Node.js
import { mkdir, readdir, stat, rm } from "fs/promises";

// إنشاء مجلد
await mkdir("./uploads", { recursive: true });

// قراءة محتويات مجلد
const files = await readdir("./src");
console.log(files);

// الحصول على معلومات مفصلة عن الملفات
const entries = await readdir("./src", { withFileTypes: true });
for (const entry of entries) {
console.log(`${entry.name} - ${entry.isDirectory() ? "مجلد" : "ملف"}`);
}

// حذف ملف أو مجلد
await rm("./temp", { recursive: true, force: true });

المسارات

للتعامل مع المسارات، يمكن استخدام وحدة path:

import { join, resolve, dirname, basename, extname } from "path";

// دمج أجزاء المسار
const fullPath = join(__dirname, "uploads", "image.jpg");

// الحصول على المسار المطلق
const absolutePath = resolve("./relative/path.txt");

// الحصول على مجلد الملف
const dir = dirname("/path/to/file.txt"); // "/path/to"

// الحصول على اسم الملف
const filename = basename("/path/to/file.txt"); // "file.txt"

// الحصول على امتداد الملف
const extension = extname("/path/to/file.txt"); // ".txt"

اختبار التطبيقات في Bun.js

يوفر Bun.js إطار اختبار مدمج سريع وسهل الاستخدام، مستوحى من أطر الاختبار الشهيرة مثل Jest. يمكنك كتابة وتشغيل الاختبارات مباشرة دون الحاجة لتثبيت أي مكتبات إضافية.

كتابة اختبارات بسيطة

يمكن كتابة اختبارات باستخدام وحدة bun:test المدمجة:

// sum.test.ts
import { test, expect } from "bun:test";

// الدالة المراد اختبارها
function sum(a: number, b: number): number {
return a + b;
}

// اختبار بسيط
test("إضافة 1 + 2 تساوي 3", () => {
expect(sum(1, 2)).toBe(3);
});

// اختبار متعدد التأكيدات
test("يجب أن تعمل الدالة مع أرقام مختلفة", () => {
expect(sum(1, 1)).toBe(2);
expect(sum(5, 7)).toBe(12);
expect(sum(-1, 1)).toBe(0);
expect(sum(0, 0)).toBe(0);
});

// اختبار للتحقق من رمي استثناء
test("يجب أن يفشل مع قيم غير صالحة", () => {
// @ts-ignore - اختبار متعمد لقيم خاطئة
expect(() => sum("a", 2)).toThrow();
});

تشغيل الاختبارات

لتشغيل جميع الاختبارات في المشروع:

# تشغيل جميع الاختبارات
bun test

# تشغيل ملف اختبار محدد
bun test sum.test.ts

# تشغيل الاختبارات بنمط معين
bun test --pattern "sum"

اختبارات غير متزامنة

يمكن كتابة اختبارات للدوال غير المتزامنة:

// async.test.ts
import { test, expect } from "bun:test";

// دالة غير متزامنة للاختبار
async function fetchData() {
return { success: true, data: [1, 2, 3] };
}

// اختبار غير متزامن
test("يجب أن تعيد بيانات بنجاح", async () => {
const result = await fetchData();

expect(result.success).toBe(true);
expect(result.data).toBeArray();
expect(result.data).toContain(2);
});

مجموعات الاختبارات

يمكن تنظيم الاختبارات في مجموعات باستخدام describe:

// math.test.ts
import { test, expect, describe } from "bun:test";

describe("اختبارات العمليات الحسابية", () => {
// اختبار الجمع
test("إضافة الأرقام", () => {
expect(1 + 2).toBe(3);
expect(5 + 5).toBe(10);
});

// اختبار الطرح
test("طرح الأرقام", () => {
expect(5 - 2).toBe(3);
expect(10 - 5).toBe(5);
});

// مجموعة فرعية من الاختبارات
describe("عمليات حسابية متقدمة", () => {
test("ضرب الأرقام", () => {
expect(2 * 3).toBe(6);
expect(4 * 5).toBe(20);
});

test("قسمة الأرقام", () => {
expect(10 / 2).toBe(5);
expect(20 / 4).toBe(5);
});
});
});

الدوال المساعدة للاختبارات

يمكن استخدام دوال beforeAll، afterAll، beforeEach، و afterEach لإعداد وتنظيف البيئة:

// hooks.test.ts
import { test, expect, beforeAll, afterAll, beforeEach, afterEach } from "bun:test";
import { createServer } from "./server";

let server;
let data = [];

// تنفيذ مرة واحدة قبل جميع الاختبارات
beforeAll(() => {
console.log("بدء تشغيل الاختبارات");
server = createServer();
});

// تنفيذ قبل كل اختبار
beforeEach(() => {
data = [1, 2, 3];
console.log("تجهيز البيانات للاختبار");
});

// تنفيذ بعد كل اختبار
afterEach(() => {
data = [];
console.log("تنظيف البيانات بعد الاختبار");
});

// تنفيذ مرة واحدة بعد جميع الاختبارات
afterAll(() => {
server.close();
console.log("انتهاء جميع الاختبارات");
});

test("اختبار البيانات", () => {
expect(data).toHaveLength(3);
data.push(4);
expect(data).toHaveLength(4);
});

test("اختبار البيانات مرة أخرى", () => {
// data سيكون [1, 2, 3] مرة أخرى بسبب beforeEach
expect(data).toHaveLength(3);
});

دعم TypeScript

توفر Bun.js دعماً مدمجاً لـ TypeScript دون الحاجة إلى تكوينات إضافية. يمكن تشغيل ملفات TypeScript مباشرة دون خطوة ترجمة منفصلة.

تشغيل ملفات TypeScript

يمكن تشغيل ملفات TypeScript مباشرة:

bun run app.ts

تكوين TypeScript

يمكن تكوين TypeScript باستخدام ملف tsconfig.json المعتاد:

{
"compilerOptions": {
"target": "ES2021",
"module": "ESNext",
"moduleResolution": "node",
"types": ["bun-types"],
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"outDir": "dist"
},
"include": ["src/**/*"]
}

إضافة أنواع Bun.js

للحصول على تعريفات الأنواع الكاملة لـ Bun.js، قم بتثبيت حزمة bun-types:

bun add -d bun-types

مثال لملف TypeScript

مثال لملف TypeScript يستخدم ميزات Bun.js:

// app.ts
import { serve } from "bun";

// تعريف واجهة البيانات
interface User {
  id: number;
  name: string;
  email: string;
  isAdmin: boolean;
}

// إنشاء قائمة بالمستخدمين
const users: User[] = [
  { id: 1, name: "أحمد", email: "[email protected]", isAdmin: true },
  { id: 2, name: "سارة", email: "[email protected]", isAdmin: false },
  { id: 3, name: "محمد", email: "[email protected]", isAdmin: false }
];

// إنشاء خادم HTTP
const server = serve({
  port: 3000,
  fetch(req): Response {
    const url = new URL(req.url);
    
    // إرجاع جميع المستخدمين
    if (url.pathname === "/api/users") {
      return Response.json(users);
    }
    
    // إرجاع مستخدم حسب المعرف
    if (url.pathname.startsWith("/api/users/")) {
      const id = parseInt(url.pathname.split("/").pop() || "0");
      const user = users.find(u => u.id === id);
      
      if (!user) {
        return new Response("لم يتم العثور على المستخدم", { status: 404 });
      }
      
      return Response.json(user);
    }
    
    return new Response("مرحبًا بك في واجهة برمجة التطبيقات!");
  }
});

console.log(`الخادم يعمل على المنفذ ${server.port}`);

دعم JSX

توفر Bun.js دعمًا مدمجًا لـ JSX، مما يسمح بتشغيل ملفات React وPreact وغيرها من المكتبات التي تستخدم JSX مباشرة دون الحاجة إلى تكوينات معقدة.

تشغيل ملفات JSX

يمكن تشغيل ملفات JSX و TSX مباشرة:

bun run app.jsx
bun run app.tsx

تكوين JSX

يمكن تخصيص تكوين JSX في ملف bunfig.toml:

[jsx]
runtime = "automatic" # أو "classic"
pragma = "h" # لـ Preact
fragmentPragma = "Fragment"

مثال لملف JSX

مثال بسيط لملف JSX مع React:

// app.jsx
import { serve } from "bun";
import React from "react";
import { renderToString } from "react-dom/server";

// مكون React بسيط
const App = ({ name }) => {
  return (
    
      
        تطبيق Bun.js مع React
      
      
        

مرحبًا بك في Bun.js!

مرحبًا يا {name}

); }; // إنشاء خادم HTTP serve({ port: 3000, fetch(req) { return new Response( renderToString(), { headers: { "Content-Type": "text/html; charset=utf-8", }, } ); } });

تطبيق React كامل

لإنشاء تطبيق React كامل، يمكنك استخدام أمر bun create:

bun create react my-react-app

ثم تشغيل التطبيق باستخدام:

cd my-react-app
bun dev

المتغيرات البيئية في Bun.js

توفر Bun.js دعمًا مدمجًا لملفات .env للتعامل مع المتغيرات البيئية. يتم تحميل هذه الملفات تلقائيًا عند تشغيل التطبيق.

ملفات .env المدعومة

تدعم Bun.js الملفات التالية، وتحملها بالترتيب الموضح أدناه (الملفات اللاحقة تحل محل القيم المتطابقة في الملفات السابقة):

  • .env: الإعدادات الافتراضية
  • .env.local: الإعدادات المحلية
  • .env.[mode]: الإعدادات الخاصة بالوضع المحدد (مثل .env.production)
  • .env.[mode].local: الإعدادات المحلية الخاصة بالوضع المحدد

مثال لملف .env

# .env
PORT=3000
DATABASE_URL=postgres://user:password@localhost:5432/mydb
API_KEY=your_secret_api_key
DEBUG=false

الوصول إلى المتغيرات البيئية

يمكن الوصول إلى المتغيرات البيئية بطريقتين:

// الطريقة الأولى: استخدام process.env (متوافق مع Node.js)
const port = process.env.PORT || 3000;
console.log(`المنفذ: ${port}`);

// الطريقة الثانية: استخدام Bun.env (خاص ببن)
const apiKey = Bun.env.API_KEY;
console.log(`مفتاح واجهة البرمجة: ${apiKey}`);

تحميل ملف .env يدويًا

يمكن أيضًا تحميل ملف .env يدويًا باستخدام:

import { config } from "bun";

// تحميل ملف .env محدد
config({ path: "./config/.env.test" });

إضافة متغيرات بيئية في سطر الأوامر

يمكن إضافة متغيرات بيئية مباشرة عند تشغيل الأمر:

PORT=4000 DEBUG=true bun run server.ts

قواعد البيانات في Bun.js

يوفر Bun.js دعمًا مدمجًا لقواعد بيانات SQLite، بالإضافة إلى إمكانية استخدام مكتبات قواعد بيانات أخرى مثل MySQL وPostgreSQL وMongoDB.

SQLite المدمج

يمكن استخدام قاعدة بيانات SQLite المدمجة في Bun.js بسهولة:

import { Database } from "bun:sqlite";

// إنشاء أو فتح قاعدة بيانات
const db = new Database("mydata.sqlite");

// إنشاء جدول
db.run(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  )
`);

// إضافة بيانات
const insertUser = db.prepare(`
  INSERT INTO users (name, email) VALUES ($name, $email)
`);

insertUser.run({
  $name: "أحمد",
  $email: "[email protected]"
});

// قراءة البيانات
const users = db.query("SELECT * FROM users").all();
console.log(users);

// استخدام استعلام معد مسبقًا مع معلمات
const getUserById = db.prepare("SELECT * FROM users WHERE id = $id");
const user = getUserById.get({ $id: 1 });
console.log(user);

// إغلاق قاعدة البيانات (اختياري)
db.close();

استخدام قواعد بيانات أخرى

يمكن استخدام حزم قواعد البيانات الأخرى مثل postgres وmysql2 وmongodb مع Bun.js:

// مثال لاستخدام PostgreSQL مع Bun.js
import postgres from "postgres";

// إنشاء اتصال
const sql = postgres("postgres://username:password@localhost:5432/database");

// استعلام بسيط
const users = await sql`SELECT * FROM users`;
console.log(users);

// إضافة سجل
const newUser = await sql`
  INSERT INTO users (name, email)
  VALUES (${"محمد"}, ${"[email protected]"})
  RETURNING *
`;

// إغلاق الاتصال عند الانتهاء
await sql.end();

مثال لاستخدام MongoDB

// مثال لاستخدام MongoDB مع Bun.js
import { MongoClient } from "mongodb";

// إنشاء اتصال
const client = new MongoClient("mongodb://localhost:27017");
await client.connect();

// الوصول إلى قاعدة البيانات والمجموعة
const db = client.db("myapp");
const users = db.collection("users");

// إضافة بيانات
await users.insertOne({
  name: "سارة",
  email: "[email protected]",
  age: 28,
  createdAt: new Date()
});

// قراءة البيانات
const allUsers = await users.find({}).toArray();
console.log(allUsers);

// إغلاق الاتصال
await client.close();

الأداء في Bun.js

تتميز Bun.js بأداء عالٍ مقارنة بـ Node.js وبيئات تشغيل JavaScript الأخرى. فيما يلي بعض نصائح الأداء والميزات التي تجعل Bun.js سريعًا.

مقارنة الأداء

تظهر الاختبارات أن Bun.js يتفوق على Node.js في العديد من المجالات:

  • وقت بدء التشغيل أسرع بـ 4 مرات
  • استهلاك أقل للذاكرة (حوالي 30-50٪ أقل)
  • سرعة أعلى في معالجة الطلبات HTTP
  • تثبيت الحزم أسرع بـ 20 مرة من npm

نصائح لتحسين الأداء

// استخدام FFI للوظائف كثيفة الحوسبة
import { dlopen, FFIType } from "bun:ffi";

// تحميل مكتبة C مثلاً للوظائف كثيفة الحوسبة
const lib = dlopen("./libcalculator.so", {
  calculate: {
    args: [FFIType.i32, FFIType.i32],
    returns: FFIType.i32
  }
});

// استدعاء الدالة المكتوبة بلغة C
const result = lib.symbols.calculate(10, 20);
console.log(result);

تعزيز أداء خادم HTTP

// استخدام التخزين المؤقت للطلبات المتكررة
import { serve } from "bun";

// إنشاء خريطة للتخزين المؤقت
const responseCache = new Map();

serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    const cacheKey = url.pathname + url.search;
    
    // التحقق من التخزين المؤقت
    if (responseCache.has(cacheKey)) {
      return responseCache.get(cacheKey);
    }
    
    // إنشاء استجابة جديدة
    const response = new Response(`مرحبًا! الوقت الحالي: ${new Date().toISOString()}`);
    
    // تخزين الاستجابة في التخزين المؤقت (لمدة معينة)
    responseCache.set(cacheKey, response);
    setTimeout(() => responseCache.delete(cacheKey), 10000); // حذف بعد 10 ثوانٍ
    
    return response;
  }
});

تشغيل عمليات متوازية

// استخدام Bun.spawn لتشغيل عمليات متوازية
import { spawn } from "bun";

async function runParallelTasks() {
  const processes = [];
  
  // تشغيل 3 عمليات متوازية
  for (let i = 0; i < 3; i++) {
    processes.push(
      spawn({
        cmd: ["bun", "run", "worker.ts", i.toString()],
        stdout: "pipe",
        env: { WORKER_ID: i.toString() }
      })
    );
  }
  
  // انتظار انتهاء جميع العمليات
  for (const proc of processes) {
    const text = await new Response(proc.stdout).text();
    console.log(`نتيجة العملية: ${text}`);
  }
}

runParallelTasks();

نصيحة للأداء الأمثل

استخدم Bun.js لتطبيقات الخادم عندما يكون الأداء أولوية قصوى. استفد من ميزات الملفات والتجزئة المدمجة لتوفير الذاكرة. تحقق دائمًا من أحدث نسخة من Bun.js حيث يتم تحسين الأداء باستمرار مع كل إصدار جديد.

كيف يمكنك المساهمة؟

Bun.js مشروع مفتوح المصدر ويرحب بالمساهمات من المجتمع. يمكنك المساهمة من خلال: