تجربة محسّنة لتصحيح الأخطاء
على مدار الأشهر القليلة الماضية، تعاون فريق "أدوات مطوري البرامج في Chrome" مع فريق Angular لإجراء تحسينات على تجربة تصحيح الأخطاء في "أدوات مطوري البرامج في Chrome". تعاون أعضاء الفريقَين معًا واتّخذوا خطوات نحو تمكين المطوّرين من تصحيح أخطاء تطبيقات الويب وتحليلها من وجهة نظر التأليف: من حيث اللغة المصدر وبنية المشروع، مع إمكانية الوصول إلى معلومات مألوفة وملائمة لهم.
تتناول هذه المشاركة التفاصيل الأساسية لمعرفة التغييرات المطلوبة في Angular و"أدوات مطوري البرامج" في Chrome لتحقيق ذلك. وعلى الرغم من توضيح بعض هذه التغييرات من خلال Angular، يمكن تطبيقها على أُطر عمل أخرى أيضًا. يشجع فريق Chrome DevTools إطارات العمل الأخرى على استخدام واجهات برمجة تطبيقات وحدة التحكّم الجديدة ونقاط إضافة خرائط المصدر حتى تتمكّن هي الأخرى من تقديم تجربة تصحيح أخطاء أفضل للمستخدمين.
رمز إدراج التجاهل
عند تصحيح أخطاء التطبيقات باستخدام "أدوات مطوري البرامج في Chrome"، يريد المؤلفون بشكل عام الاطّلاع على الرمز البرمجي فقط، وليس رمز إطار العمل الأساسي أو بعض التبعيات المخفية في مجلد node_modules
.
لتحقيق ذلك، قدّم فريق "أدوات مطوّري البرامج" إضافةً إلى خرائط المصادر، تُعرف باسم x_google_ignoreList
. تُستخدَم هذه الإضافة لتحديد المصادر التابعة لجهات خارجية، مثل رمز إطار العمل أو الرمز الذي ينشئه أداة تجميع الحِزم. عندما يستخدم إطار عمل هذه الإضافة، يمكن للمؤلفين الآن تجنُّب الرمز البرمجي الذي لا يريدون رؤيته أو التنقّل فيه تلقائيًا بدون الحاجة إلى ضبط هذا الإعداد يدويًا مسبقًا.
من الناحية العملية، يمكن أن تخفي "أدوات مطوّري البرامج في Chrome" تلقائيًا الرمز البرمجي الذي تم تحديده على هذا النحو في عمليات تتبُّع تسلسل استدعاء الدوال البرمجية وشجرة "المصادر" ومربّع الحوار "الفتح السريع"، كما يمكنها تحسين سلوك التنقّل إلى الخطوة التالية واستئناف التنفيذ في أداة تصحيح الأخطاء.
إضافة خريطة المصدر "x_google_ignoreList
"
في خرائط المصدر، يشير الحقل x_google_ignoreList
الجديد إلى المصفوفة sources
، ويسرد فهارس كل المصادر المعروفة التابعة لجهات خارجية في خريطة المصدر هذه. عند تحليل خريطة المصدر، ستستخدِم أدوات مطوّري برامج Chrome هذه المعلومات لمعرفة الأقسام التي يجب إدراجها في قائمة العناصر التي يتم تجاهلها من الرمز البرمجي.
في ما يلي خريطة مصادر للملف الذي تم إنشاؤه out.js
. هناك نوعان من sources
أصلي ساهما في إنشاء ملف الناتج: foo.js
وlib.js
. الأول هو رمز برمجي كتبه مطوّر موقع إلكتروني، والثاني هو إطار عمل استخدمه.
{
"version" : 3,
"file": "out.js",
"sourceRoot": "",
"sources": ["foo.js", "lib.js"],
"sourcesContent": ["...", "..."],
"names": ["src", "maps", "are", "fun"],
"mappings": "A,AAAB;;ABCDE;"
}
يتم تضمين sourcesContent
لكلا المصدرَين الأصليَين، وستعرِض "أدوات مطوّري البرامج في Chrome" هذه الملفات تلقائيًا في "أداة تصحيح الأخطاء":
- كملفات في شجرة "المصادر"
- كنتائج في مربّع الحوار "الفتح السريع"
- مثل المواقع الجغرافية لإطارات المكالمات التي تم ربطها في عمليات تتبُّع تسلسل استدعاء الدوال البرمجية، وذلك أثناء الإيقاف المؤقت عند نقطة إيقاف وأثناء التحرك.
هناك معلومة إضافية يمكن الآن تضمينها في خرائط المصادر لتحديد أيّ من هذه المصادر هو رمز أساسي أو تابع لجهة خارجية:
{
...
"sources": ["foo.js", "lib.js"],
"x_google_ignoreList": [1],
...
}
يحتوي حقل x_google_ignoreList
الجديد على فهرس واحد يشير إلى المصفوفة sources
: 1. يحدِّد ذلك أنّ المناطق التي تمّ ربطها بـ lib.js
هي في الواقع رمز تابع لجهة خارجية يجب إضافته تلقائيًا إلى قائمة التجاهل.
في مثال أكثر تعقيدًا، كما هو موضّح أدناه، يحدّد الفهرسان 2 و4 و5 أنّ المناطق التي تمّ ربطها بالرمز lib1.ts
وlib2.coffee
وhmr.js
كلها رموز تابعة لجهات خارجية يجب إضافتها تلقائيًا إلى قائمة العناصر التي سيتم تجاهلها.
{
...
"sources": ["foo.html", "bar.css", "lib1.ts", "baz.js", "lib2.coffee", "hmr.js"],
"x_google_ignoreList": [2, 4, 5],
...
}
إذا كنت مطوّرًا لإطار عمل أو أداة تجميع، تأكَّد من أنّ خرائط المصدر التي يتم إنشاؤها أثناء عملية الإنشاء تتضمّن هذا الحقل من أجل الاستفادة من هذه الإمكانات الجديدة في "أدوات مطوّري البرامج" في Chrome.
x_google_ignoreList
في Angular
بدءًا من الإصدار 14.1.0 من Angular، تم وضع علامة "تجاهل" على محتوى المجلد node_modules
وwebpack
.
وقد تم تحقيق ذلك من خلال تغيير في angular-cli
من خلال إنشاء مكوّن إضافي يثبّت وحدة Compiler
في حزمة الويب.
إنّ مكوّن webpack الإضافي الذي أنشأه مهندسونا يربط مرحلة PROCESS_ASSETS_STAGE_DEV_TOOLING
ويملؤه حقل x_google_ignoreList
في خرائط المصدر لمواد العرض النهائية التي ينشئها webpack ويحمّلها المتصفّح.
const map = JSON.parse(mapContent) as SourceMap;
const ignoreList = [];
for (const [index, path] of map.sources.entries()) {
if (path.includes('/node_modules/') || path.startsWith('webpack/')) {
ignoreList.push(index);
}
}
map[`x_google_ignoreList`] = ignoreList;
compilation.updateAsset(name, new RawSource(JSON.stringify(map)));
عمليات تتبُّع تسلسل استدعاء الدوال البرمجية المرتبطة
يجيب تتبُّع تسلسل استدعاء الدوال البرمجية على سؤال "كيف وصلت إلى هنا"، ولكن في كثير من الأحيان يكون ذلك من منظور الجهاز، وليس بالضرورة مع شيء يناسب منظور مطوّر البرامج أو نموذجه العقلي لوقت تشغيل التطبيق. وينطبق ذلك بشكل خاص عندما يتم جدولة بعض العمليات لاحقًا بشكل غير متزامن: قد يكون من المفيد معرفة "الأسباب الأساسية" أو الجانب المتعلق بالجدولة لهذه العمليات، ولكن هذا هو بالضبط ما لن يكون جزءًا من تتبُّع تسلسل استدعاء الدوال البرمجية غير المتزامن.
يحتوي V8 داخليًا على آلية لتتبُّع هذه المهام غير المتزامنة عند استخدام العناصر الأساسية لجدولة المتصفّح العادية، مثل setTimeout
. ويتم إجراء ذلك تلقائيًا في هذه الحالات، حتى يتمكّن المطوّرون من فحصها. ولكن في المشاريع الأكثر تعقيدًا، لا يكون الأمر بهذه البساطة، خاصة عند استخدام إطار عمل يتضمّن آليات جدولة أكثر تقدمًا، مثل إطار عمل يتتبّع المناطق أو يصطفّ المهام المخصّصة أو يقسّم التعديلات إلى عدّة وحدات عمل يتم تنفيذها بمرور الوقت.
لحلّ هذه المشكلة، توفّر "أدوات مطوّري البرامج" آلية تُسمّى "Async Stack Tagging API" على الكائن console
، وتتيح لمطوّري إطار العمل إضافة تلميحات إلى المواقع الجغرافية التي تتم جدولة العمليات فيها والأماكن التي يتم فيها تنفيذ هذه العمليات.
Async Stack Tagging API
بدون ميزة "وضع علامات على تسلسل استدعاء الدوال البرمجية غير المتزامنة"، تظهر عمليات تتبُّع تسلسل استدعاء الدوال البرمجية للرمز البرمجي الذي يتم تنفيذه بشكل غير متزامن بطرق معقّدة من خلال إطارات العمل بدون أي صلة بالرمز البرمجي الذي تم تحديد موعد تنفيذه.
باستخدام ميزة "وضع علامات على تسلسل استدعاء الدوال البرمجية غير المتزامنة"، من الممكن تقديم هذا السياق، ويظهر تسلسل استدعاء الدوال البرمجية على النحو التالي:
لتحقيق ذلك، استخدِم طريقة console
جديدة باسم console.createTask()
توفّرها واجهة برمجة التطبيقات Async Stack Tagging API. توقيعه كما يلي:
interface Console {
createTask(name: string): Task;
}
interface Task {
run<T>(f: () => T): T;
}
يؤدي استدعاء console.createTask()
إلى إرجاع مثيل Task
يمكنك استخدامه لاحقًا لتشغيل الرمز غير المتزامن.
// Task Creation
const task = console.createTask(name);
// Task Execution
task.run(f);
يمكن أيضًا تداخل العمليات غير المتزامنة، وسيتم عرض "الأسباب الأساسية" في تتبع تسلسل استدعاء الدوال البرمجية بالتسلسل.
يمكن تنفيذ المهام أي عدد من المرات ويمكن أن تختلف الحمولة في كل عملية تنفيذ. سيتم تذكُّر حزمة الاستدعاءات في موقع الجدولة إلى أن يصبح كائن المهمة غير مرغوب فيه.
واجهة برمجة التطبيقات Async Stack Tagging API في Angular
في Angular، تم إجراء تغييرات على NgZone، وهو سياق تنفيذ Angular الذي يستمر في جميع المهام غير المتزامنة.
عند جدولة مهمة، يتم استخدام console.createTask()
عند توفّرها. يتم تخزين مثيل Task
الناتج لاستخدامه في المستقبل. بعد استدعاء المهمة، ستستخدم NgZone مثيل Task
المخزّن لتشغيلها.
تم تضمين هذه التغييرات في الإصدار 0.11.8 من NgZone في Angular من خلال طلبَي سحب #46693 و#46958.
إطارات المكالمات الودية
غالبًا ما تُنشئ الإطارات البرمجية رموزًا من جميع أنواع لغات النماذج عند إنشاء مشروع، مثل نماذج Angular أو JSX التي تحوّل الرمز الذي يبدو مثل HTML إلى JavaScript عادي يتم تشغيله في النهاية في المتصفّح. في بعض الأحيان، يتم منح هذه الأنواع من الدوالّ التي تم إنشاؤها أسماءً غير مألوفة، إما أسماءً مكونة من حرف واحد بعد تصغيرها أو أسماءً مبهمة أو غير مألوفة حتى في حال عدم تصغيرها.
في Angular، من الشائع رؤية إطارات استدعاء بأسماء مثل AppComponent_Template_app_button_handleClick_1_listener
في عمليات تتبُّع تسلسل استدعاء الدوال البرمجية.
لحلّ هذه المشكلة، تتيح الآن أدوات Chrome المطوّرين إعادة تسمية هذه الدوالّ من خلال خرائط المصدر. إذا كانت خريطة المصدر تحتوي على إدخال اسم لبداية نطاق الدالة (أي القوس الأيسر لقائمة المَعلمات)، يجب أن يعرض إطار الاستدعاء هذا الاسم في تتبُّع تسلسل استدعاء الدوال البرمجية.
إطارات المكالمات الودية في Angular
إنّ إعادة تسمية إطارات المكالمات في Angular هي جهد مستمر. نتوقّع أن يتم طرح هذه التحسينات تدريجيًا بمرور الوقت.
أثناء تحليل نماذج HTML التي كتبها المؤلفون، ينشئ المحول البرمجي Angular رمز TypeScript، والذي يتم نقله في النهاية إلى رمز JavaScript الذي يحمّله المتصفّح ويشغِّله.
وكجزء من عملية إنشاء الرموز البرمجية هذه، يتم أيضًا إنشاء خرائط المصادر. نستكشف حاليًا طرقًا لتضمين أسماء الدوالّ في حقل "الأسماء" في خرائط المصدر، والإشارة إلى هذه الأسماء في عمليات الربط بين الرمز الذي تم إنشاؤه والرمز الأصلي.
على سبيل المثال، إذا تم إنشاء دالة لمُستمع أحداث وكان اسمها غير مألوف أو تمت إزالته أثناء التصغير، يمكن الآن أن تتضمّن خرائط المصدر الاسم الأكثر ملاءمةً لهذه الدالة في حقل "الأسماء"، ويمكن أن يشير تعيين بداية نطاق الدالة الآن إلى هذا الاسم (أي القوس الأيسر لقائمة المَعلمات). ستستخدم Chrome DevTools بعد ذلك هذه الأسماء لإعادة تسمية إطارات الاستدعاء في عمليات تتبُّع تسلسل استدعاء الدوال البرمجية.
نظرة مستقبلية
لقد كانت تجربة رائعة استخدام Angular كبرنامج تجريبي لإثبات صحة عملنا. يسرّنا معرفة رأي مطوّري الإطارات الأساسية وتلقّي ملاحظاتهم بشأن نقاط التوسيع هذه.
هناك المزيد من المجالات التي نريد استكشافها. وعلى وجه الخصوص، كيفية تحسين تجربة إعداد الملفات الشخصية في "أدوات مطوّري البرامج"