اخبار وب

Bun چیست؟ قابلیت‌ها، سازگاری و ارزیابی سرعت برای پروژه واقعی

راهنمای کاربردی Bun و تفاوت Runtime با Package Manager؛ سازگاری Node.js، اجرای TypeScript، نمونه سرور کامل و معیارهای خواندن Benchmark.

1404/11/03 2 دقیقه مطالعه 1,254 بازدید
Bun چیست؟ قابلیت‌ها، سازگاری و ارزیابی سرعت برای پروژه واقعی

Bun مجموعه‌ای از ابزارهای توسعه JavaScript است که Runtime، Package Manager، Bundler و Test Runner را کنار هم ارائه می‌کند. این ترکیب برای تیمی که چند ابزار جداگانه را تنظیم می‌کند جذاب است، اما عنوان «Bun 2.0 و رکوردشکنی سرعت» بدون پیوند به انتشار مشخص و روش Benchmark، مبنای مناسبی برای انتخاب نیست. در این راهنما درباره قابلیت‌های مستند Bun و روش ارزیابی آن برای یک پروژه واقعی صحبت می‌کنیم. اعداد مقایسه‌ای متن قبلی حذف شده‌اند، چون نسخه ابزارها، سخت‌افزار و کد اندازه‌گیری همراه آن‌ها نبود.

Runtime را از ابزارهای همراه جدا کنید

Runtime محیطی است که برنامه JavaScript را اجرا می‌کند. Bun برای این کار از JavaScriptCore استفاده می‌کند، در حالی که Node.js بر V8 تکیه دارد. تفاوت موتور به تنهایی برنده همه برنامه‌ها را تعیین نمی‌کند. برنامه‌ای که بیشتر وقتش را منتظر پایگاه داده می‌ماند، با برنامه‌ای که محاسبه سنگین انجام می‌دهد یکسان نیست. شروع فرایند، مدیریت ارتباط HTTP و مصرف حافظه هم بخش‌های جداگانه‌ای از عملکرد هستند. هنگام مقایسه باید معلوم باشد درباره کدام رفتار صحبت می‌کنید.

Package Manager وابستگی‌ها را نصب و نسخه‌های انتخاب‌شده را ثبت می‌کند. Bundler فایل‌های برنامه را برای خروجی مشخص ترکیب می‌کند و Test Runner آزمون‌ها را اجرا می‌کند. ممکن است تیم فقط Package Manager Bun را به کار بگیرد و برنامه را همچنان با Node.js اجرا کند. ممکن است پروژه دیگری از Runtime و Bundler هم استفاده کند. معرفی رسمی Bun این مجموعه قابلیت‌ها را توضیح می‌دهد؛ انتخاب هر بخش را جدا انجام دهید تا تغییر ابزار نصب، ناخواسته به تغییر محیط اجرای تولید تبدیل نشود.

این جداسازی برای عیب‌یابی هم مفید است. اگر بعد از جابه‌جایی ابزار نصب مشکلی پیش آمد، ابتدا نسخه واقعی وابستگی‌ها، lockfile و اسکریپت‌های نصب را بررسی کنید. اگر Runtime عوض شده است، رفتار APIها و کتابخانه‌های استفاده‌شده را هم مرور کنید. تغییر هم‌زمان همه اجزا تشخیص علت را سخت می‌کند. یک مهاجرت محدود که هدفش کاهش اصطکاک نصب است، الزاماً نیازی به تغییر سرور برنامه ندارد. هدف تغییر را پیش از انتخاب فرمان‌ها روی کاغذ بنویسید.

سازگاری با Node.js شرط دارد

Bun تلاش می‌کند با APIها و رفتارهای Node.js سازگار باشد. این تلاش با ادعای برابری کامل در تمام جزئیات فرق دارد. صفحه سازگاری رسمی وضعیت ماژول‌ها و محدودیت‌های شناخته‌شده را فهرست می‌کند. اگر برنامه به قابلیت خاصی مثل ابزار تشخیص حافظه، اجرای فرایند فرزند یا افزونه بومی وابسته است، همان قابلیت را در این صفحه پیدا کنید. عبارت عمومی «جایگزین Node.js» برای نتیجه‌گیری درباره مسیر حساس یک برنامه کافی نیست.

وابستگی‌ها نیز ممکن است بر فرض‌هایی درباره محیط اجرا بنا شده باشند. کتابخانه‌ای که در سطح API به Node.js وابسته است، می‌تواند در بخشی از ابزار ساخت یا نصب به رفتار متفاوتی تکیه کند. وجود فایل lockfile و نصب موفق به معنی پوشش همه این مسیرها نیست. برای تصمیم عملی، فهرست وابستگی‌های مستقیم را مرور کنید و آن‌هایی را که اتصال شبکه، فایل، رمزنگاری یا binding بومی دارند جدا علامت بزنید. این فهرست محدوده بررسی را قابل فهم می‌کند و جلوی بحث مبهم درباره سازگاری را می‌گیرد.

در پروژه‌هایی که ابزارهای توسعه و تولید متفاوت‌اند، نسخه Runtime باید در مستندات و تنظیمات استقرار مشخص باشد. اگر توسعه‌دهنده محلی با Bun کار می‌کند و سرور با Node.js اجرا می‌شود، نباید API اختصاصی Bun وارد مسیر اجرای سرور شود، مگر اینکه معماری عمداً این وابستگی را پذیرفته باشد. نام فایل TypeScript یا JavaScript این تفاوت را پنهان نمی‌کند. قرارداد محیط اجرا بخشی از قرارداد پروژه است و باید برای همکار بعدی هم روشن بماند.

اجرای TypeScript با بررسی نوع فرق دارد

Bun می‌تواند فایل TypeScript را اجرا کند و بخش‌های نوع را برای اجرا کنار بگذارد. این رفتار به معنی انجام Type Checking کامل نیست. کدی ممکن است قابل اجرا باشد، اما قرارداد نوعی نادرستی داشته باشد که فقط در یک ورودی خاص به خطا تبدیل شود. اگر پروژه از TypeScript برای کنترل این قراردادها استفاده می‌کند، مرحله بررسی نوع را نگه دارید. حذف آن فقط به دلیل موفقیت اجرای فایل، معنای استفاده از TypeScript را عوض می‌کند.

تنظیمات compiler و نوع‌های محیط نیز باید با مقصد هماهنگ باشند. برنامه مرورگر، برنامه سرور و ابزار خط فرمان مجموعه یکسانی از globalها ندارند. اگر نوع‌های Bun را در پروژه‌ای که باید با Node.js هم اجرا شود وارد می‌کنید، مراقب باشید پیشنهاد تکمیل خودکار شما را به API اختصاصی هدایت نکند. مقاله الگوهای پیشرفته TypeScript درباره قراردادهای نوع و مرز داده توضیح بیشتری می‌دهد. ابزار اجرای سریع جای طراحی این مرزها را نمی‌گیرد.

یک نمونه کامل برای شناخت رفتار Runtime

نمونه زیر یک سرور کوچک HTTP است که مسیر ریشه، مسیر سلامت و پاسخ پیدا نشدن را پوشش می‌دهد. وابستگی خارجی ندارد و از API اختصاصی Bun استفاده می‌کند؛ بنابراین همان فایل را با Node.js اجرا نکنید. فایل را با نام server.ts ذخیره کنید. پس از نصب Bun از راهنمای رسمی، در پوشه فایل فرمان bun run server.ts را وارد کنید و نشانی http://localhost:3000 را در مرورگر باز کنید. این نمونه آموزشی است و نتیجه Benchmark یا تنظیم تولید محسوب نمی‌شود.

const port = Number(process.env.PORT ?? 3000);
if (!Number.isInteger(port) || port < 1 || port > 65535) {
  throw new Error("PORT must be an integer between 1 and 65535");
}
const server = Bun.serve({
  port,
  fetch(request) {
    const url = new URL(request.url);
    if (request.method !== "GET") {
      return new Response("Method not allowed", {
        status: 405,
        headers: { Allow: "GET" },
      });
    }
    if (url.pathname === "/health") {
      return Response.json({ status: "ok" });
    }
    if (url.pathname === "/") {
      return Response.json({ message: "Hello from Bun" });
    }
    return new Response("Not found", { status: 404 });
  },
});
console.log(`Server listening at ${server.url}`);

مقدار PORT اختیاری است و در نبود آن برنامه از 3000 استفاده می‌کند. اگر پورت اشغال باشد، باید برنامه دیگری را متوقف کنید یا پورت دیگری بدهید. مسیر health فقط پاسخ ثابت برای معرفی مسیریابی دارد؛ سلامت پایگاه داده یا سرویس بیرونی را بررسی نمی‌کند. پاسخ ریشه JSON است و مسیرهای ناشناخته وضعیت 404 می‌گیرند. ساختار کوچک نمونه کمک می‌کند تفاوت میان راه‌اندازی سرور، انتخاب مسیر و تولید پاسخ را ببینید، بدون اینکه تنظیمات یک فریمورک دیگر در توضیح دخالت کند.

برای تبدیل این نمونه به سرویس واقعی، نیازمندی‌ها را جدا تعیین کنید: اعتبارسنجی ورودی، مدیریت خطا، محدودیت اندازه درخواست و ثبت رخداد. اگر داده شخصی دریافت می‌شود، قواعد نگهداری و حذف آن هم باید مشخص باشد. افزودن endpoint جدید فقط اضافه‌کردن یک شرط مسیر نیست؛ باید قرارداد پاسخ و رفتار خطا را بنویسید. مقاله الگوهای طراحی API ادامه این بحث را پوشش می‌دهد. Runtime انتخاب‌شده این قرارداد را خودکار برای شما تعریف نمی‌کند.

اعداد سرعت را چگونه بخوانیم؟

Benchmark وقتی قابل تفسیر است که workload و شرایطش روشن باشد. تعداد درخواست در ثانیه برای پاسخ ثابت، اندازه‌گیری سرعت یک فروشگاه با احراز هویت و پایگاه داده نیست. گاهی تست اتصال را دوباره استفاده می‌کند و گاهی برای هر درخواست اتصال تازه می‌سازد. Warm-up، حجم پاسخ و تعداد workerها هم روی نتیجه اثر دارند. اگر گزارش این اطلاعات را نداده است، عددش را به وعده عملکرد پروژه خود تبدیل نکنید. برای مقایسه، هر دو ابزار باید کار برابر انجام دهند.

میانگین تأخیر تمام تجربه کاربر را توضیح نمی‌دهد. درخواست‌های کند، مصرف حافظه در بار طولانی و رفتار هنگام اشباع منابع نیز مهم‌اند. برنامه ممکن است در بار معمول سریع باشد و با افزایش بار صف طولانی ایجاد کند. از گزارش آزمایش بخواهید محدودیت منابع، مدت اجرا و توزیع تأخیر را نشان دهد. نتیجه یک دستگاه توسعه را بدون بررسی محیط استقرار تعمیم ندهید؛ محدودیت CPU، شبکه و ذخیره‌سازی سرور می‌تواند گلوگاه متفاوتی بسازد.

سرعت نصب وابستگی هم شاخص دیگری است. نصب با cache گرم با نصب اولیه در محیط خالی فرق دارد. اگر هدف کوتاه‌ترکردن pipeline است، سهم نصب را از کل زمان ساخت جدا ببینید. ممکن است بخش اصلی زمان در دانلود تصویر container یا ساخت frontend صرف شود. در چنین وضعی، تغییر Package Manager نتیجه‌ای کمتر از انتظار دارد. داده مرتبط با مسئله خود را ثبت کنید و از نسبت‌های تبلیغاتی برای محاسبه صرفه‌جویی زمان تیم استفاده نکنید.

مهاجرت را با مرز روشن انجام دهید

نخست وضعیت فعلی را مستند کنید: فرمان نصب، فرمان build، محیط تولید و وابستگی‌های مهم. سپس یک بخش مستقل مثل ابزار توسعه یا سرویس کوچک را انتخاب کنید. lockfile و نسخه ابزار باید همراه تغییر ثبت شوند تا همکاران بتوانند نصب یکسانی انجام دهند. اگر هدف فقط تجربه توسعه است، این هدف را در توضیح تغییر بنویسید. چنین توضیحی به بازبین کمک می‌کند ببیند مهاجرت چه مسئله‌ای را حل کرده و کدام ادعا هنوز نیاز به داده دارد.

مسیر بازگشت نیز باید ساده باشد. تنظیمات قبلی را بشناسید و بدانید کدام فایل‌ها به Bun وابسته شده‌اند. کدی که از Bun.serve استفاده می‌کند به تغییر Runtime وابسته است، ولی بسیاری از توابع پردازش داده ممکن است وابستگی اختصاصی نداشته باشند. مرز این دو را حفظ کنید. در تیم بزرگ، امکان استفاده مشترک از ابزار مهم‌تر از ترجیح یک توسعه‌دهنده است. مستندات کوتاه نصب و اجرای پروژه کمک می‌کند تغییر به دانشی شفاهی میان چند نفر محدود نشود.

برای انتخاب نسخه، از صفحه انتشار رسمی و نیازمندی پروژه استفاده کنید. نسخه و تاریخ بررسی را ثبت کنید و وجود یک نسخه آینده را از عنوان مقاله فرض نگیرید. اگر یک قابلیت فقط در نسخه مشخصی آمده است، همان محدودیت را کنار تنظیم مربوط بنویسید. Bun برای پروژه‌هایی که از ترکیب ابزارهایش سود می‌برند گزینه قابل بررسی است؛ تصمیم نهایی باید از سازگاری وابستگی‌ها، هزینه نگهداری و رفتار workload خودتان بیاید، نه از یک ادعای رکوردشکنی بدون روش اندازه‌گیری.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!