تجربة محسّنة لتصحيح الأخطاء
خلال الأشهر القليلة الماضية، تعاون فريق "أدوات مطوّري البرامج في 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
اعتبارًا من Angular v14.1.0، تم وضع علامة "للتجاهل" على محتوى المجلدَين node_modules
وwebpack
.
تم تحقيق ذلك من خلال تغيير في angular-cli
من خلال إنشاء مكوّن إضافي يرتبط بوحدة Compiler
في webpack.
إنّ مكوّن 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
. ويتم إجراء ذلك تلقائيًا في هذه الحالات، حتى يتمكّن المطوّرون من فحصها. ولكن في المشاريع الأكثر تعقيدًا، لا يكون الأمر بهذه البساطة، خاصة عند استخدام إطار عمل يتضمّن آليات جدولة أكثر تقدمًا، مثل إطار عمل يتتبّع المناطق أو يصطفّ المهام المخصّصة أو يقسّم التعديلات إلى عدّة وحدات عمل يتم تنفيذها بمرور الوقت.
لحلّ هذه المشكلة، تعرِض DevTools آلية تُعرف باسم "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 كبرنامج تجريبي لإثبات صحة عملنا. يسرّنا معرفة رأي مطوّري الإطارات وتلقّي ملاحظاتهم بشأن نقاط التوسيع هذه.
هناك المزيد من المجالات التي نريد استكشافها. وعلى وجه الخصوص، كيفية تحسين تجربة إعداد الملفات الشخصية في "أدوات مطوّري البرامج"