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

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

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

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

مثال لمكتبة خرائط المصدر بلغة Mozilla JavaScript أثناء تنفيذها

واقع

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

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

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

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

لماذا عليّ الاهتمام بخرائط المصدر؟

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

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

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

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

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

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

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

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

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

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

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

في الوقت الحالي، لا يضيف المحول البرمجي للإغلاق التعليق الخاص في النهاية المطلوب للإشارة إلى أدوات مطوّري البرامج من المتصفحات بأنّ خريطة المصدر متوفّرة:

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

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

إذا لم تعجبك فكرة التعليق الغريب، يمكنك بدلاً من ذلك تعيين عنوان خاص على ملف 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، وسنتعمّق في مزيد من التفاصيل حول كيفية عمل قسم "التعيينات". يتضمن المثال التالي تباينًا طفيفًا عن مثال مواصفات 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. يسمح لك بت المتابعة بالبناء على قيمة شريحة، بحيث يمكنك تخزين أرقام كبيرة دون الحاجة إلى تخزين رقم كبير، وهو أسلوب ذكي لتوفير المساحة وله جذور بتنسيق ميدي.

بعد معالجة الرسم البياني أعلاه 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 لعرض كيفية فك ترميز الشرائح. ويمكنك أيضًا الاطّلاع على رمز ربط المصدر المكتوب أيضًا بلغة JavaScript في أدوات WebKit dev.

لفهم كيفية الحصول على القيمة 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 ومجهولة الهوية

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

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

العرض التوضيحي: عرض الرمز البرمجي eval() كنص برمجي من خلال sourceURL

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

ويتيح لك المساعد الآخر تسمية الدوال المجهولة باستخدام السمة 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). ومع ذلك، فوتر العرضName إلى حد كبير في الماء ولن ينتقل إلى Chrome. ولكن لم تفقد كل الأمل، تم اقتراح اقتراح أفضل بكثير اسمه debugName.

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

لِنتعاوَن معًا

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

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

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

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

إنه ليس مثاليًا

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

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

المشاكل

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

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

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

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

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

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