Skip to content

يتحدث Bun بروتوكول WebKit Inspector، لذا يمكنك تنقيح الكود الخاص بك باستخدام أداة تنقيح تفاعلية. لأغراض العرض، ضع في اعتبارك خادم الويب البسيط التالي.

تنقيح JavaScript و TypeScript

typescript
Bun.serve({
  fetch(req) {
    console.log(req.url);
    return new Response("Hello, world!");
  },
});

--inspect

لتمكين التنقيح عند تشغيل الكود باستخدام Bun، استخدم العلم --inspect. هذا يبدأ تلقائيًا خادم WebSocket على منفذ متاح يمكن استخدامه لفحص عملية Bun الجارية.

sh
bun --inspect server.ts
txt
------------------ Bun Inspector ------------------
Listening at:
  ws://localhost:6499/0tqxs9exrgrm

Inspect in browser:
  https://debug.bun.sh/#localhost:6499/0tqxs9exrgrm
------------------ Bun Inspector ------------------

--inspect-brk

يتصرف العلم --inspect-brk بشكل مطابق لـ --inspect، باستثناء أنه يحقن تلقائيًا نقطة توقف في السطر الأول من النص البرمجي المنفَّذ. هذا مفيد لتنقيح النصوص البرمجية التي تعمل بسرعة وتخرج فورًا.

--inspect-wait

يتصرف العلم --inspect-wait بشكل مطابق لـ --inspect، باستثناء أن الكود لن يُنفَّذ حتى يتم إرفاق أداة تنقيح بعملية Bun الجارية.

تعيين منفذ أو URL لأداة التنقيح

بغض النظر عن العلم الذي تستخدمه، يمكنك اختياريًا تحديد رقم منفذ أو بادئة URL أو كليهما.

sh
bun --inspect=4000 server.ts
bun --inspect=localhost:4000 server.ts
bun --inspect=localhost:4000/prefix server.ts

أدوات التنقيح

يمكن لأدوات التنقيح المختلفة الاتصال بهذا الخادم لتوفير تجربة تنقيح تفاعلية.

debug.bun.sh

يستضيف Bun أداة تنقيح قائمة على الويب على debug.bun.sh. إنها نسخة معدلة من واجهة Web Inspector الخاصة بـ WebKit، والتي ستبدو مألوفة لمستخدمي Safari.

افتح عنوان URL debug.bun.sh المقدم في متصفحك لبدء جلسة تنقيح. من هذه الواجهة، ستتمكن من عرض الكود المصدري للملف الجاري تشغيله، وعرض نقاط التوقف وتعيينها، وتنفيذ الكود باستخدام وحدة التحكم المدمجة.

دعنا نضع نقطة توقف. انتقل إلى علامة التبويب Sources؛ يجب أن ترى الكود من السابق. انقر على رقم السطر 3 لوضع نقطة توقف على عبارة console.log(req.url) الخاصة بنا.

ثم قم بزيارة http://localhost:3000 في متصفح الويب الخاص بك. سيرسل هذا طلب HTTP إلى خادم الويب localhost الخاص بنا. سيبدو وكأن الصفحة لا يتم تحميلها. لماذا؟ لأن البرنامج أوقف التنفيذ عند نقطة التوقف التي وضعناها سابقًا.

لاحظ كيف تغيرت واجهة المستخدم.

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

على الجانب الأيمن من لوحة Sources، يمكننا رؤية جميع المتغيرات المحلية الموجودة حاليًا في النطاق، والتعمق لرؤية خصائصها وطرقها. هنا، نقوم بفحص المتغير req.

في الجزء العلوي الأيسر من لوحة Sources، يمكننا التحكم في تنفيذ البرنامج.

إليك غش يشرح وظائف أزرار التحكم في التدفق.

  • Continue script execution — مواصلة تشغيل البرنامج حتى نقطة التوقف أو الاستثناء التالي.
  • Step over — سيستمر البرنامج إلى السطر التالي.
  • Step into — إذا كانت العبارة الحالية تحتوي على استدعاء دالة، فستدخل أداة التنقيح "إلى" الدالة المستدعاة.
  • Step out — إذا كانت العبارة الحالية استدعاء دالة، فستنهي أداة التنقيح تنفيذ الاستدعاء، ثم "تخرج" من الدالة إلى الموقع الذي تم استدعاؤها منه.

أداة تنقيح Visual Studio Code

يتوفر دعم تجريبي لتنقيح نصوص Bun البرمجية في Visual Studio Code. لاستخدامه، ستحتاج إلى تثبيت إضافة Bun لـ VSCode.


تنقيح طلبات الشبكة

تتيح لك متغير البيئة BUN_CONFIG_VERBOSE_FETCH تسجيل طلبات الشبكة التي تم إجراؤها باستخدام fetch() أو node:http تلقائيًا.

القيمةالوصف
curlطباعة الطلبات كأوامر curl.
trueطباعة معلومات الطلب والاستجابة
falseعدم طباعة أي شيء. الافتراضي

طباعة طلبات fetch و node:http كأوامر curl

يدعم Bun أيضًا طباعة طلبات الشبكة fetch() و node:http كأوامر curl عن طريق تعيين متغير البيئة BUN_CONFIG_VERBOSE_FETCH إلى curl. هذا يطبع طلب fetch كسطر واحد من أمر curl للسماح لك بالنسخ واللصق في طرفيتك لتكرار الطلب.

ts
process.env.BUN_CONFIG_VERBOSE_FETCH = "curl";

await fetch("https://example.com", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ foo: "bar" }),
});
txt
[fetch] $ curl --http1.1 "https://example.com/" -X POST -H "content-type: application/json" -H "Connection: keep-alive" -H "User-Agent: Bun/1.3.3" -H "Accept: */*" -H "Host: example.com" -H "Accept-Encoding: gzip, deflate, br" --compressed -H "Content-Length: 13" --data-raw "{\"foo\":\"bar\"}"
[fetch] > HTTP/1.1 POST https://example.com/
[fetch] > content-type: application/json
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[fetch] > Accept: */*
[fetch] > Host: example.com
[fetch] > Accept-Encoding: gzip, deflate, br
[fetch] > Content-Length: 13

[fetch] < 200 OK
[fetch] < Accept-Ranges: bytes
[fetch] < Cache-Control: max-age=604800
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Date: Tue, 18 Jun 2024 05:12:07 GMT
[fetch] < Etag: "3147526947"
[fetch] < Expires: Tue, 25 Jun 2024 05:12:07 GMT
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
[fetch] < Server: EOS (vny/044F)
[fetch] < Content-Length: 1256

السطور التي تحتوي على [fetch] > هي الطلب من الكود المحلي الخاص بك، والسطور التي تحتوي على [fetch] < هي الاستجابة من الخادم البعيد.

يدعم متغير البيئة BUN_CONFIG_VERBOSE_FETCH في كل من طلبات fetch() و node:http، لذا يجب أن يعمل فقط.

للطباعة بدون أمر curl، عيّن BUN_CONFIG_VERBOSE_FETCH إلى true.

ts
process.env.BUN_CONFIG_VERBOSE_FETCH = "true";

await fetch("https://example.com", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ foo: "bar" }),
});
txt
[fetch] > HTTP/1.1 POST https://example.com/
[fetch] > content-type: application/json
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[fetch] > Accept: */*
[fetch] > Host: example.com
[fetch] > Accept-Encoding: gzip, deflate, br
[fetch] > Content-Length: 13

[fetch] < 200 OK
[fetch] < Accept-Ranges: bytes
[fetch] < Cache-Control: max-age=604800
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Date: Tue, 18 Jun 2024 05:12:07 GMT
[fetch] < Etag: "3147526947"
[fetch] < Expires: Tue, 25 Jun 2024 05:12:07 GMT
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
[fetch] < Server: EOS (vny/044F)
[fetch] < Content-Length: 1256

تتبع الأخطاء وخرائط المصدر

يقوم Bun بترجمة كل ملف، مما قد يعني أن تتبع الأخطاء الذي تراه في وحدة التحكم سيشير بشكل غير مفيد إلى المخرجات المترجمة. لمعالجة ذلك، يقوم Bun تلقائيًا بإنشاء وتقديم ملفات ذات خرائط مصدر لكل ملف يترجمه. عندما ترى تتبع خطأ في وحدة التحكم، يمكنك النقر على مسار الملف والانتقال إلى الكود المصدري الأصلي، حتى لو كان مكتوبًا بـ TypeScript أو JSX، أو لديه بعض التحويلات الأخرى المطبقة.

يقوم Bun تلقائيًا بتحميل خرائط المصدر سواء في وقت التشغيل عند ترجمة الملفات عند الطلب، وعند استخدام bun build لترجمة الملفات مسبقًا.

معاينة الكود المصدري مع تمييز الصيغة

للمساعدة في التنقيح، يطبع Bun تلقائيًا معاينة صغيرة للكود المصدري عند حدوث استثناء أو رفض غير معالج. يمكنك محاكاة هذا السلوك عن طريق استدعاء Bun.inspect(error):

ts
// إنشاء خطأ
const err = new Error("Something went wrong");
console.log(Bun.inspect(err, { colors: true }));

هذا يطبع معاينة مميزة الصيغة للكود المصدري حيث حدث الخطأ، جنبًا إلى جنب مع رسالة الخطأ وتتبع الخطأ.

ts
1 | // إنشاء خطأ
2 | const err = new Error("Something went wrong");
                ^
error: Something went wrong
      at file.js:2:13

تتبع أخطاء V8

يستخدم Bun JavaScriptCore كمحرك له، لكن الكثير من نظام Node.js البيئي و npm يتوقعان V8. تختلف محركات JavaScript في تنسيق error.stack. ينوي Bun أن يكون بديلاً مباشرًا لـ Node.js، وهذا يعني أنه من مسؤوليتنا التأكد من أنه على الرغم من اختلاف المحرك، فإن تتبع الأخطاء متشابهة قدر الإمكان.

لهذا السبب عند تسجيل error.stack في Bun، فإن تنسيق error.stack هو نفسه كما في محرك V8 الخاص بـ Node.js. هذا مفيد بشكل خاص عند استخدام المكتبات التي تتوقع تتبع أخطاء V8.

واجهة برمجة تطبيقات تتبع أخطاء V8

يطبق Bun واجهة برمجة تطبيقات تتبع أخطاء V8، وهي مجموعة من الدوال التي تتيح لك التلاعب بتتبع الأخطاء.

Error.prepareStackTrace

دالة Error.prepareStackTrace هي دالة عامة تتيح لك تخصيص مخرجات تتبع الخطأ. يتم استدعاء هذه الدالة مع كائن الخطأ ومصفوفة من كائنات CallSite وتتيح لك إرجاع تتبع خطأ مخصص.

ts
Error.prepareStackTrace = (err, stack) => {
  return stack.map(callSite => {
    return callSite.getFileName();
  });
};

const err = new Error("Something went wrong");
console.log(err.stack);
// [ "error.js" ]

يحتوي كائن CallSite على الطرق التالية:

الطريقةالإرجاع
getThisقيمة this لاستدعاء الدالة
getTypeNametypeof this
getFunctionكائن الدالة
getFunctionNameاسم الدالة كسلسلة
getMethodNameاسم الطريقة كسلسلة
getFileNameاسم الملف أو URL
getLineNumberرقم السطر
getColumnNumberرقم العمود
getEvalOriginundefined
getScriptNameOrSourceURLURL المصدر
isToplevelترجع true إذا كانت الدالة في النطاق العام
isEvalترجع true إذا كانت الدالة استدعاء eval
isNativeترجع true إذا كانت الدالة أصلية
isConstructorترجع true إذا كانت الدالة منشئًا
isAsyncترجع true إذا كانت الدالة async
isPromiseAllلم يتم تنفيذها بعد.
getPromiseIndexلم يتم تنفيذها بعد.
toStringترجع تمثيلًا نصيًا لموقع الاستدعاء

في بعض الحالات، قد يكون كائن Function قد تم جمع القمامة بالفعل، لذا قد ترجع بعض هذه الطرق undefined.

Error.captureStackTrace(error, startFn)

تتيح لك دالة Error.captureStackTrace التقاط تتبع خطأ عند نقطة محددة في الكود الخاص بك، بدلاً من النقطة التي تم فيها رمي الخطأ.

يمكن أن يكون هذا مفيدًا عندما يكون لديك استدعاءات رد أو كود غير متزامن يجعل من الصعب تحديد مصدر الخطأ. الوسيطة الثانية لـ Error.captureStackTrace هي الدالة التي تريد أن يبدأ عندها تتبع الخطأ.

على سبيل المثال، سيجعل الكود أدناه err.stack يشير إلى الكود الذي يستدعي fn()، على الرغم من أن الخطأ تم رميه في myInner.

ts
const fn = () => {
  function myInner() {
    throw err;
  }

  try {
    myInner();
  } catch (err) {
    console.log(err.stack);
    console.log("");
    console.log("-- captureStackTrace --");
    console.log("");
    Error.captureStackTrace(err, fn);
    console.log(err.stack);
  }
};

fn();
txt
Error: here!
    at myInner (file.js:4:15)
    at fn (file.js:8:5)
    at module code (file.js:17:1)
    at moduleEvaluation (native)
    at moduleEvaluation (native)
    at <anonymous> (native)

-- captureStackTrace --

Error: here!
    at module code (file.js:17:1)
    at moduleEvaluation (native)
    at moduleEvaluation (native)
    at <anonymous> (native)

Bun بواسطة www.bunjs.com.cn تحرير