مقدمة إلى خرائط مصادر JavaScript

ريان سيددون

هل تمنيت يومًا أن يظلّ الرمز البرمجي من جهة العميل قابلاً للقراءة والأهم من ذلك أنّه قابل للتصحيح حتى بعد دمجه وتصغيره، بدون التأثير في الأداء؟ الآن يمكنك ذلك من خلال الميزات الرائعة في خرائط المصدر.

خرائط المصدر هي طريقة لإعادة ربط ملف مجمّع/مصغّر إلى حالته غير المنشأة. عند الإنشاء للإنتاج، مع تصغير ملفات JavaScript ودمجها، يمكنك إنشاء خريطة مصدر تحتوي على معلومات حول ملفاتك الأصلية. عند إجراء طلب بحث عن رقم سطر وعمود معيّن في JavaScript الذي أنشأته، يمكنك إجراء بحث في خريطة المصدر التي تعرِض الموقع الأصلي. يمكن لأدوات المطوّرين (حاليًا إصدارات WebKit الليلية أو Google Chrome أو Firefox 23 والإصدارات الأحدث) تحليل خريطة المصدر تلقائيًا وجعلها تظهر كما لو كنت تشغِّل ملفات غير مصغَّرة وغير مدمجة.

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

مثال لمكتبة خريطة مصدر JavaScript من Mozilla بشكل عملي

العالم الحقيقي

قبل عرض التطبيق الحقيقي التالي لخرائط المصدر، تأكد من تمكين ميزة خرائط المصدر إما في Chrome Canary أو WebKit ليلاً من خلال النقر على ترس الإعدادات في لوحة أدوات مطوّري البرامج وتحديد خيار "تمكين خرائط المصدر".

كيفية تفعيل خرائط المصدر في أدوات مطوّري برامج WebKit.

تتضمّن الإصدار 23 من Firefox والإصدارات الأحدث خرائط المصدر مفعَّلة تلقائيًا في أدوات مطوّري البرامج المضمَّنة.

كيفية تفعيل خرائط المصدر في أدوات مطوّري البرامج في Firefox

لماذا يجب أن أهتم بخرائط المصدر؟

في الوقت الحالي، يعمل ربط المصدر فقط بين لغة JavaScript غير المضغوطة/المدمجة إلى لغة JavaScript المضغوطة/غير المجمّعة، ولكن المستقبل سيبدو مشرقًا مع الحديث عن لغات البرمجة المجمَّعة إلى JavaScript مثل CoffeeScript، بل وإمكانية إضافة دعم للمعالجات المسبقة لـ CSS، مثل SASS أو LESS.

في المستقبل، يمكننا بسهولة استخدام أي لغة تقريبًا على الرغم من توافقها محليًا في المتصفح مع خرائط المصدر:

  • CoffeeScript
  • ECMAScript 6 والإصدارات الأحدث
  • SASS/أقل وغير ذلك
  • تقريبًا أي لغة يتم تجميعها إلى JavaScript

ألق نظرة على هذا التسجيل الرقمي للشاشة أثناء تصحيح أخطاء CoffeeScript في إصدار تجريبي لوحدة تحكم Firefox:

أضافت مجموعة أدوات الويب من Google (GWT) مؤخرًا دعمًا لخرائط المصدر. أجرى راي كرومويل من فريق GWT تسجيلاً رقميًا رائعًا يعرض دعم خرائط المصدر بشكل عملي.

المثال الآخر الذي أعددته هو مكتبة Traceur من Google التي تتيح لك كتابة ES6 (ECMAScript 6 أو Next) وتجميعها في رمز متوافق مع ES3. يُنشئ المحول البرمجي لـ Traceur خريطة مصدر أيضًا. ألقِ نظرة على هذا العرض التوضيحي لسمات وصفوف ES6 التي يتم استخدامها كما لو أنّها متوفّرة في الأصل في المتصفّح، وذلك بفضل خريطة المصدر.

تسمح لك مساحة النص في العرض التوضيحي أيضًا بكتابة ES6 التي سيتم تجميعها بسرعة وإنشاء خريطة مصدر بالإضافة إلى رمز ES3 المكافئ.

تتبع تصحيح الأخطاء ES6 باستخدام خرائط المصدر.

عرض توضيحي: كتابة ES6 وتصحيح أخطائها والاطّلاع على ربط المصدر عمليًا

كيف تعمل خريطة المصادر؟

أما برنامج تجميع/تصغير JavaScript الوحيد الذي يتوفر له دعم في الوقت الحالي لإنشاء خريطة المصدر، فهو المحول البرمجي للإغلاق. (سأشرح كيفية استخدامها لاحقًا). بعد دمج JavaScript وتصغيره، سيتمّ إنشاء ملف خريطة مصدر بجانبه.

في الوقت الحالي، لا يضيف المحول البرمجي لـ Closure

//# sourceMappingURL=/path/to/file.js.map

ويتيح ذلك لأدوات المطوّرين إعادة ربط المكالمات بموقعها الجغرافي في الملفات المصدر الأصلية. في السابق، كانت عبارة التعليق "//@"، ولكن بسبب بعض المشاكل في ذلك وتعليقات التجميع المشروط، لذلك تم اتّخاذ قرار بتغييرها إلى //#. ويدعم Chrome Canary وWebKit Nightly وFirefox 24 والإصدارات الأحدث حاليًا صفحة التعليقات الجديدة. يؤثر تغيير البنية أيضًا في عنوان URL المصدر.

إذا لم تعجبك فكرة هذا التعليق الغريب، يمكنك بدلاً من ذلك تعيين رأس خاص على ملف JavaScript المجمَّع:

X-SourceMap: /path/to/file.js.map

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

مثال على WebKit Devtools لخرائط المصدر وتفعيل خرائط المصدر وإيقافها.

لن يتم تنزيل ملف خريطة المصدر إلا في حال تفعيل خرائط المصدر وفتح أدوات مطوّري البرامج. وستحتاج أيضًا إلى تحميل ملفاتك الأصلية كي تتمكّن أدوات مطوّري البرامج من الرجوع إليها وعرضها عند الضرورة.

كيف يمكنني إنشاء خريطة مصادر؟

ستحتاج إلى استخدام مجمع الإغلاق لتصغير وربط وإنشاء خريطة مصدر لملفات JavaScript. يكون الأمر على النحو التالي:

java -jar compiler.jar \
--js script.js \
--create_source_map ./script-min.js.map \
--source_map_format=V3 \
--js_output_file script-min.js

علامتا الأوامر المهمتان هما --create_source_map و--source_map_format. هذا مطلوب لأن الإصدار الافتراضي هو V2 ونريد العمل مع V3 فقط.

بنية خريطة المصدر

لفهم خريطة المصدر بشكل أفضل، سنأخذ مثالاً صغيرًا على ملف خريطة مصدر سيتم إنشاؤه بواسطة المحول البرمجي لـ Closure وسوف نتعمق في المزيد من التفاصيل حول كيفية عمل قسم "mappings" (التعيينات). يعتبر المثال التالي تباينًا طفيفًا عن مثال مواصفات V3.

{
    version : 3,
    file: "out.js",
    sourceRoot : "",
    sources: ["foo.js", "bar.js"],
    names: ["src", "maps", "are", "fun"],
    mappings: "AAgBC,SAAQ,CAAEA"
}

يمكنك أن ترى أعلاه أن خريطة المصدر عبارة عن كائن حرفيًا يحتوي على الكثير من المعلومات الغنية:

  • رقم الإصدار الذي تستند إليه خريطة المصدر
  • اسم ملف الرمز الذي تم إنشاؤه (ملف الإنتاج المصغَّر/المدمج)
  • يتيح لك sourceRoot إضافة المصادر ببنية مجلد، وهذا أيضًا أسلوب لتوفير المساحة.
  • تحتوي المصادر على جميع أسماء الملفات التي تم دمجها.
  • تحتوي على جميع أسماء المتغيرات/الطرق التي تظهر في جميع أنحاء التعليمات البرمجية.
  • وأخيرًا، خاصية التعيينات هي المكان الذي يحدث فيه السحر باستخدام قيم Base64 VLQ. يتم توفير المساحة الفعلية هنا.

Base64 VLQ والحفاظ على خريطة المصدر صغيرة

في الأصل، كان لمواصفات خريطة المصدر مخرجات مطولة للغاية لجميع التعيينات وأدت إلى حجم خريطة المصدر بحوالي 10 أضعاف حجم الكود الذي تم إنشاؤه. وقد أدى الإصدار الثاني إلى خفض هذا العدد بحوالي 50% بينما أدى الإصدار الثالث إلى خفضه مرة أخرى بنسبة 50% أخرى. إذًا بالنسبة إلى ملف حجمه 133 كيلوبايت، انتهى الأمر بخريطة مصدر تبلغ حوالي 300 كيلوبايت.

إذن كيف قاموا بتقليل الحجم مع الحفاظ على التعيينات المعقدة؟

يتم استخدام VLQ (كمية الطول المتغيّر) مع ترميز القيمة إلى قيمة Base64. خاصية التعيينات عبارة عن سلسلة كبيرة جدًا. توجد داخل هذه السلسلة فواصل منقوطة (;) تمثل رقم سطر داخل الملف الذي تم إنشاؤه. توجد داخل كل سطر فواصل (،) تمثل كل جزء داخل هذا الخط. وتكون كل شريحة من هذه الشرائح إما 1 أو 4 أو 5 في حقول متغيرة الطول. وقد تظهر بعضها أطول ولكنها تحتوي على أجزاء من موضوع المتابعة. يعتمد كل جزء على المقطع السابق، مما يساعد في تقليل حجم الملف حيث يكون كل بت نسبيًا مع الأجزاء السابقة له.

تقسيم لجزء ضمن ملف JSON لخريطة المصدر.

كما ذكرنا أعلاه، يمكن أن تكون كل شريحة 1 أو 4 أو 5 بطول متغير. يعتبر هذا الرسم التخطيطي طولاً متغيرًا من أربعة مع بت متابعة واحد (g). سنقوم بتفصيل هذا الجزء وتوضيح كيفية حساب خريطة المصدر للموقع الأصلي.

القيم المعروضة أعلاه هي قيم Base64 التي تم فك ترميزها بشكلٍ حصري، وهناك بعض المعالجة الإضافية للحصول على القيم الحقيقية. وعادةً ما تنجح كل شريحة من خمسة أشياء:

  • عمود تم إنشاؤه
  • الملف الأصلي الذي ظهر فيه هذا
  • رقم السطر الأصلي
  • العمود الأصلي
  • والاسم الأصلي، إن توفَّر

ليس لكل مقطع اسم أو اسم طريقة أو وسيطة، ولذلك سيتم تبديل المقاطع في جميع الأجزاء بين أربعة وخمسة متغيرات طولها. قيمة g في مخطط الشريحة أعلاه هي ما يسمى بت المتابعة وهو ما يسمح بمزيد من التحسين في مرحلة فك ترميز Base64 VLQ. يسمح لك بت المتابعة بالبناء على قيمة شريحة بحيث يمكنك تخزين الأرقام الكبيرة دون الحاجة إلى تخزين رقم كبير، وهو أسلوب ذكي للغاية لتوفير المساحة له جذوره في تنسيق mediai.

بعد معالجة الرسم التخطيطي أعلاه AAgBC بشكل إضافي، سيعرض 0، 0، 32، 16، 1 - يمثل 32 وحدة الاستمرار التي تساعد في إنشاء القيمة التالية وهي 16. قيمة B التي تم فك ترميزها تمامًا في Base64 هي 1. لذا فإن القيم المهمة المستخدمة هي 0، 0، 16، 1. يتيح لنا ذلك بعد ذلك معرفة أن السطر 1 (يتم الاحتفاظ بحساب السطور باستخدام الفواصل المنقوطة) في العمود 0 من الملف الذي تم إنشاؤه، ويتم تعيينه للملف 0 (صفيف الملفات 0 هو foo.js)، والسطر 16 في العمود 1.

لتوضيح كيفية فك ترميز المقاطع، سأشير إلى مكتبة JavaScript لخريطة المصدر في Mozilla. يمكنك أيضًا الاطّلاع على رمز تعيين المصدر لأدوات مطوّري برامج WebKit، والمكتوب أيضًا بلغة JavaScript.

لكي نفهم بشكل صحيح كيف نحصل على القيمة 16 من B، يجب أن نحصل على فهم أساسي للعوامل المختلفة البت وكيفية عمل المواصفات لتعيين المصدر. يتم الإشارة إلى الرقم السابق، g، كعنصر متابعة من خلال مقارنة الرقم (32) وVLQ_CONTINUATION_BIT (ثنائي 100000 أو 32) باستخدام عامل التشغيل AND (&).

32 & 32 = 32
// or
100000
|
|
V
100000

ويكون هذا ناتجًا عن 1 في كل موضع بت حيث يظهر عليه كلاهما. وبالتالي، فإنّ القيمة التي تم فك ترميزها لـ Base64 والتي تبلغ 33 & 32 ستعرض 32 لأنّها تشترك فقط في الموضع 32 بت كما يظهر في الرسم التخطيطي أعلاه. بعد ذلك، يؤدي ذلك إلى زيادة قيمة shift البت بمقدار 5 لكل بت متابعة سابقة. في الحالة المذكورة أعلاه، تم إزاحته بمقدار 5 مرة فقط، وبالتالي فإن إزاحة اليسار 1 (B) بمقدار 5.

1 <<../ 5 // 32

// Shift the bit by 5 spots
______
|    |
V    V
100001 = 100000 = 32

ثم يتم تحويل هذه القيمة من قيمة موقعة VLQ عن طريق تحريك الرقم (32) مكان واحد إلى اليمين.

32 >> 1 // 16
//or
100000
|
 |
 V
010000 = 16

وهذا كل ما في الأمر: هذه هي الطريقة التي يصبح بها الرقم 1 إلى 16. قد تبدو هذه عملية أكثر تعقيدًا، ولكن بمجرد أن تبدأ الأرقام في الزيادة، يكون من المنطقي أكثر ذلك.

مشاكل XSSI المحتملة

تشير المواصفات إلى مشاكل تضمين النصوص البرمجية للمواقع الإلكترونية المختلفة التي قد تنشأ من استخدام خريطة مصدر. للحدّ من هذه المشكلة، ننصحك بإضافة ")]}" في بداية السطر الأول من خريطة المصدر، وذلك من أجل إبطال صلاحية JavaScript عمدًا لكي يتم عرض خطأ في البنية. يمكن لأدوات مطوري WebKit التعامل مع هذا الأمر بالفعل.

if (response.slice(0, 3) === ")]}") {
    response = response.substring(response.indexOf('\n'));
}

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

sourceURL وdisplayName في العمل: دوال Eval ودوال مجهولة الهوية

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

يبدو المساعد الأول مشابهًا جدًا للسمة //# sourceMappingURL وقد تم ذكره في مواصفات خريطة المصدر V3. من خلال تضمين التعليق الخاص التالي في الرمز البرمجي الخاص بك، والذي سيتم تقييمه، يمكنك تسمية evals حتى تظهر كأسماء منطقية أكثر في أدوات مطوّري البرامج. اطلع على عرض توضيحي بسيط باستخدام المحول البرمجي لـ CoffeeScript:

عرض توضيحي: يمكنك الاطّلاع على رمز eval() الذي يظهر كنص برمجي عبر عنوان URL المصدر.

//# sourceURL=sqrt.coffee
شكل التعليق الخاص بعنوان URL المصدر في أدوات المطوّرين

يتيح لك المساعد الآخر تسمية الدوال المجهولة باستخدام السمة displayName المتاحة في السياق الحالي للدالة المجهولة. أنشِئ العرض التوضيحي التالي للاطّلاع على السمة displayName قيد الاستخدام.

btns[0].addEventListener("click", function(e) {
    var fn = function() {
        console.log("You clicked button number: 1");
    };

    fn.displayName = "Anonymous function of button 1";

    return fn();
}, false);
يتم الآن عرض خاصية DisplayName بشكل عملي.

عند إنشاء ملف شخصي للرمز الخاص بك ضمن أدوات المطوّرين، سيتم عرض السمة displayName بدلاً من عرض محتوى مثل (anonymous). ومع ذلك، فإن قيمة DisplayName (اسم العرض) ميتة إلى حد كبير في المياه ولن يتم إدخالها في Chrome. ولكن لا يضيع كل الأمل، وقد تم اقتراح اقتراح أفضل بكثير اسمه debugName.

وبدءًا من الكتابة، لا تتوفر التسمية eval إلا في متصفحي Firefox وWebKit. لا يتوفّر الموقع الإلكتروني displayName إلا في ليالي WebKit.

لِنتجمع معًا

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

هناك مشكلة في خريطة المصدرفي UglifyJS التي يجب مراجعتها أيضًا.

تنشئ الكثير من tools خرائط مصدر، بما في ذلك أداة تجميع نصوص القهوة. أعتبر هذه نقطة منهجية الآن.

كلما زادت الأدوات المتاحة لنا التي يمكنها إنشاء خرائط مصدر، تحسنت حالتك، لذلك تواصل واسأل أو أضف دعم خريطة المصدر إلى مشروعك المفضل مفتوح المصدر.

إنها ليست مثالية

هناك شيء لا تلبيه خرائط المصدر في الوقت الحالي هو تعبيرات المشاهدة. تكمن المشكلة في أن محاولة فحص وسيطة أو اسم متغير ضمن سياق التنفيذ الحالي لن تعرض أي شيء لأنه غير موجود حقًا. ويتطلّب هذا نوعًا من التعيين العكسي للبحث عن الاسم الحقيقي للوسيطة/المتغير الذي تريد فحصه مقارنةً باسم الوسيطة/المتغير الفعلي في JavaScript المجمّع.

هذه مشكلة قابلة للحلّ بالطبع، ومع المزيد من الاهتمام بخرائط المصدر، يمكننا البدء في رؤية بعض الميزات الرائعة وتحقيق استقرار أفضل.

المشاكل

أضاف الإصدار jQuery 1.9 مؤخرًا توافقًا مع خرائط المصدر عند عرضه خارج شبكات توصيل المحتوى (CDN) الرسمية. وأشار أيضًا إلى خطأ خاص عند استخدام تعليقات التجميع الشرطي في IE (//@cc_on) قبل تحميل jQuery. ومنذ ذلك الحين، تم الالتزام بالحدّ من هذه المشكلة من خلال إحاطة sourceMappingURL بتعليق متعدد الأسطر. الدرس الذي يجب تعلمه لا يستخدم التعليق الشرطي.

ومنذ ذلك الحين، تمت معالجة ذلك من خلال تغيير البنية إلى //#.

الأدوات والمراجع

فيما يلي بعض الموارد والأدوات الإضافية التي يجب الاطلاع عليها:

تُعَد خرائط المصدر أداة فعالة جدًا في مجموعة أدوات مطوّري البرامج. من المفيد للغاية أن تكون قادرًا على الحفاظ على رشاقة تطبيق الويب لديك مع إمكانية تصحيح الأخطاء فيه بسهولة. وهو يُعدّ أداة تعليمية فعّالة للغاية بالنسبة إلى المطوّرين الجُدد لمعرفة مدى خبرة المطوّرين في تصميم تطبيقاتهم وكتابة تطبيقاتهم بدون الحاجة إلى البحث في رموز برمجية مصغّرة غير قابلة للقراءة.

ماذا تنتظر؟ بدء إنشاء خرائط المصدر لجميع المشاريع الآن!