مقدمه ای بر نقشه های منبع جاوا اسکریپت

آیا تا به حال آرزو کرده اید که بتوانید کد سمت مشتری خود را خوانا و مهمتر از آن قابل اشکال زدایی نگه دارید، حتی پس از اینکه آن را ترکیب کردید و آن را کوچک کردید، بدون اینکه تأثیری بر عملکرد داشته باشید؟ خوب حالا شما می توانید از طریق جادوی نقشه های منبع .

نقشه های منبع راهی برای نگاشت یک فایل ترکیبی/مینی شده به حالت ساخته نشده است. هنگامی که برای تولید می‌سازید، همراه با کوچک‌سازی و ترکیب فایل‌های جاوا اسکریپت، یک نقشه منبع تولید می‌کنید که اطلاعات فایل‌های اصلی شما را در خود نگه می‌دارد. هنگامی که یک خط و شماره ستون خاص را در جاوا اسکریپت تولید شده خود جستجو می کنید، می توانید در نقشه منبع جستجو کنید که مکان اصلی را برمی گرداند. ابزارهای برنامه‌نویس (در حال حاضر نسخه‌های شبانه WebKit، Google Chrome، یا Firefox 23+) می‌توانند نقشه منبع را به‌طور خودکار تجزیه کنند و طوری به نظر برسند که گویی در حال اجرای فایل‌های ترکیب نشده و ترکیب نشده هستید.

نسخه ی نمایشی به شما این امکان را می دهد که در هر نقطه از ناحیه متنی حاوی منبع تولید شده کلیک راست کنید. انتخاب "دریافت موقعیت اصلی" نقشه منبع را با عبور از خط تولید شده و شماره ستون پرس و جو می کند و موقعیت را در کد اصلی باز می گرداند. مطمئن شوید که کنسول شما باز است تا بتوانید خروجی را ببینید.

نمونه ای از کتابخانه نقشه منبع جاوا اسکریپت موزیلا در عمل.

دنیای واقعی

قبل از مشاهده پیاده‌سازی نقشه‌های منبع در دنیای واقعی زیر، مطمئن شوید که ویژگی نقشه‌های منبع را در Chrome Canary یا WebKit شبانه با کلیک کردن روی دکمه تنظیمات در پانل ابزار توسعه و علامت زدن گزینه «فعال کردن نقشه‌های منبع» فعال کرده‌اید.

نحوه فعال کردن نقشه های منبع در ابزار توسعه WebKit.

فایرفاکس 23+ دارای نقشه های منبع است که به طور پیش فرض در ابزارهای توسعه یافته داخلی فعال شده است.

نحوه فعال کردن نقشه های منبع در ابزارهای توسعه دهنده فایرفاکس.

چرا باید به نقشه های منبع اهمیت بدهم؟

در حال حاضر نگاشت منبع فقط بین جاوا اسکریپت فشرده/ترکیب تا جاوا اسکریپت فشرده/غیرترکیب کار می کند، اما آینده با صحبت در مورد زبان های کامپایل شده به جاوا اسکریپت مانند CoffeeScript و حتی امکان اضافه کردن پشتیبانی برای پیش پردازنده های CSS مانند SASS یا LESS روشن به نظر می رسد. .

در آینده می‌توانیم تقریباً از هر زبانی به‌راحتی استفاده کنیم، گویی که به صورت بومی در مرورگر با نقشه‌های منبع پشتیبانی می‌شود:

  • CoffeeScript
  • ECMAScript 6 و بالاتر
  • SASS/LESS و دیگران
  • تقریباً هر زبانی که به جاوا اسکریپت کامپایل می شود

به این اسکرین‌کست از CoffeeScript که در یک ساخت آزمایشی کنسول فایرفاکس اشکال زدایی شده است، نگاهی بیندازید:

Google Web Toolkit (GWT) اخیراً پشتیبانی از Source Maps را اضافه کرده است. ری کرامول از تیم GWT یک اسکرین‌کست فوق‌العاده انجام داد که پشتیبانی از نقشه منبع را در عمل نشان می‌داد.

مثال دیگری که من گردآوری کرده‌ام از کتابخانه Traceur Google استفاده می‌کند که به شما امکان می‌دهد ES6 (ECMAScript 6 یا Next) بنویسید و آن را به کد سازگار با ES3 کامپایل کنید. کامپایلر Traceur همچنین یک نقشه منبع تولید می کند. نگاهی به این نسخه ی نمایشی از ویژگی ها و کلاس های ES6 بیندازید که به لطف نقشه منبع، به طور بومی در مرورگر پشتیبانی می شوند.

منطقه متنی موجود در نسخه نمایشی همچنین به شما امکان می‌دهد ES6 را بنویسید که به سرعت کامپایل می‌شود و یک نقشه منبع به اضافه کد ES3 معادل ایجاد می‌کند.

اشکال زدایی Traceur ES6 با استفاده از نقشه های منبع.

نسخه ی نمایشی: ES6 را بنویسید، آن را اشکال زدایی کنید، نقشه منبع را در عمل مشاهده کنید

نقشه منبع چگونه کار می کند؟

تنها کامپایلر/مینی‌فایر جاوا اسکریپت که در حال حاضر از تولید نقشه منبع پشتیبانی می‌کند، کامپایلر Closure است. (من بعداً نحوه استفاده از آن را توضیح خواهم داد.) هنگامی که جاوا اسکریپت خود را ترکیب و کوچک کردید، یک فایل نقشه منبع در کنار آن وجود خواهد داشت.

در حال حاضر، کامپایلر Closure نظر خاصی را در انتها اضافه نمی کند که به ابزارهای توسعه دهنده مرورگرها نشان دهد که نقشه منبع در دسترس است:

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

این به ابزارهای توسعه‌دهنده امکان می‌دهد تا تماس‌ها را به مکان خود در فایل‌های منبع اصلی نگاشت کنند. قبلاً پراگما کامنت //@ بود، اما به دلیل برخی مشکلات مربوط به آن و نظرات کامپایل شرطی IE، تصمیم به تغییر آن به //# گرفته شد . در حال حاضر Chrome Canary، WebKit Nightly و Firefox 24+ از پراگما نظرات جدید پشتیبانی می‌کنند. این تغییر نحو بر sourceURL نیز تأثیر می گذارد.

اگر ایده کامنت عجیب و غریب را دوست ندارید، می توانید یک هدر ویژه در فایل جاوا اسکریپت کامپایل شده خود تنظیم کنید:

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

مانند نظر، این به مصرف کننده نقشه منبع شما می گوید که کجا باید نقشه منبع مرتبط با یک فایل جاوا اسکریپت را جستجو کند. این هدر همچنین مشکل ارجاع نقشه های منبع را در زبان هایی که از نظرات تک خطی پشتیبانی نمی کنند، حل می کند.

WebKit Devtools مثالی از نقشه های منبع روشن و نقشه های منبع خاموش.

فایل نقشه منبع فقط در صورتی دانلود می شود که نقشه های منبع را فعال کرده باشید و ابزار توسعه دهنده شما باز باشد. همچنین باید فایل های اصلی خود را آپلود کنید تا ابزارهای توسعه دهنده بتوانند در صورت لزوم به آنها مراجعه کرده و نمایش دهند.

چگونه یک نقشه منبع تولید کنم؟

شما باید از کامپایلر Closure برای کوچک کردن، ادغام و ایجاد یک نقشه منبع برای فایل های جاوا اسکریپت خود استفاده کنید. دستور به شرح زیر است:

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 به شما امکان می دهد منابع را با ساختار پوشه اضافه کنید - این نیز یک تکنیک صرفه جویی در فضا است
  • منابع شامل تمام نام فایل هایی است که ترکیب شده اند
  • names شامل همه نام‌های متغیر/روش است که در کد شما ظاهر می‌شود.
  • در نهایت ویژگی mappings جایی است که جادو با استفاده از مقادیر Base64 VLQ اتفاق می‌افتد. صرفه جویی در فضای واقعی در اینجا انجام می شود.

Base64 VLQ و کوچک نگه داشتن نقشه منبع

در اصل، مشخصات نقشه منبع خروجی بسیار دقیقی از تمام نگاشتها داشت و منجر به این شد که نقشه منبع حدود 10 برابر اندازه کد تولید شده باشد. نسخه دو آن را حدود 50 درصد کاهش داد و نسخه 3 دوباره آن را 50 درصد دیگر کاهش داد، بنابراین برای یک فایل 133 کیلوبایتی، یک نقشه منبع ~ 300 کیلوبایتی خواهید داشت.

بنابراین چگونه آنها اندازه را کاهش دادند در حالی که هنوز نقشه های پیچیده را حفظ کردند؟

VLQ (مقدار طول متغیر) همراه با رمزگذاری مقدار در یک مقدار Base64 استفاده می شود. ویژگی mappings یک رشته فوق العاده بزرگ است. در این رشته، نقطه ویرگول (;) وجود دارد که نشان دهنده یک شماره خط در فایل تولید شده است. در هر خط، کاما (،) وجود دارد که هر بخش را در آن خط نشان می دهد. هر یک از این بخش ها در فیلدهای با طول متغیر 1، 4 یا 5 هستند. برخی ممکن است طولانی تر به نظر برسند اما اینها حاوی بیت های ادامه هستند. هر بخش بر اساس قسمت قبلی ساخته می شود، که به کاهش اندازه فایل کمک می کند زیرا هر بیت نسبت به بخش های قبلی خود است.

تفکیک یک بخش در فایل JSON نقشه منبع.

همانطور که در بالا ذکر شد، هر بخش می تواند 1، 4 یا 5 در طول متغیر باشد. این نمودار به طول متغیر چهار با یک بیت ادامه (g) در نظر گرفته می شود. ما این بخش را تجزیه می‌کنیم و به شما نشان می‌دهیم که نقشه منبع چگونه مکان اصلی را نشان می‌دهد.

مقادیر نشان داده شده در بالا صرفاً مقادیر رمزگشایی شده Base64 هستند، پردازش بیشتری برای بدست آوردن مقادیر واقعی آنها وجود دارد. هر بخش معمولاً پنج چیز را انجام می دهد:

  • ستون ایجاد شده
  • فایل اصلی این در ظاهر شد
  • شماره خط اصلی
  • ستون اصلی
  • و در صورت وجود نام اصلی

هر بخش دارای نام، نام متد یا آرگومان نیست، بنابراین بخش‌های سرتاسر بین چهار تا پنج طول متغیر تغییر می‌کنند. مقدار g در نمودار قطعه بالا چیزی است که بیت ادامه نامیده می شود و بهینه سازی بیشتر در مرحله رمزگشایی Base64 VLQ را امکان پذیر می کند. یک بیت ادامه به شما امکان می دهد تا بر روی یک مقدار بخش بسازید تا بتوانید اعداد بزرگ را بدون نیاز به ذخیره یک عدد بزرگ ذخیره کنید، یک تکنیک بسیار هوشمندانه صرفه جویی در فضا که ریشه در فرمت midi دارد.

نمودار بالا AAgBC پس از پردازش بیشتر، 0، 0، 32، 16، 1 را برمی گرداند - 32 بیت ادامه ای است که به ساخت مقدار زیر 16 کمک می کند. 0، 0، 16، 1. سپس به ما می دانیم که خط 1 (خطوط با نیم دونقطه شمارش می شوند) ستون 0 از نقشه های فایل تولید شده به فایل 0 (آرایه فایل های 0 foo.js است)، خط 16 در ستون 1.

برای نشان دادن نحوه رمزگشایی قطعات ، به کتابخانه جاوا اسکریپت نقشه منبع موزیلا ارجاع خواهم داد. همچنین می توانید به کد منبع نگاشت ابزارهای توسعه دهنده WebKit که در جاوا اسکریپت نیز نوشته شده است نگاه کنید.

برای اینکه به درستی بفهمیم که چگونه مقدار 16 را از B دریافت می کنیم، باید درک اولیه ای از عملگرهای بیتی و نحوه عملکرد مشخصات برای نگاشت منبع داشته باشیم. رقم قبل، g، با مقایسه رقم (32) و VLQ_CONTINUATION_BIT (باینری 100000 یا 32) با استفاده از عملگر بیتی AND (&) به عنوان یک بیت ادامه علامت گذاری می شود.

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

این یک 1 را در هر موقعیت بیتی که هر دو آن را نشان می دهند، برمی گرداند. بنابراین مقدار رمزگشایی شده Base64 33 & 32 32 را برمی گرداند زیرا آنها فقط مکان 32 بیتی را به اشتراک می گذارند همانطور که در نمودار بالا مشاهده می کنید. سپس مقدار تغییر بیت را برای هر بیت ادامه قبلی 5 افزایش می دهد. در حالت فوق فقط یک بار 5 جابجا می شود، بنابراین جابجایی 1 (B) به 5 به چپ.

1 <<../ 5 // 32

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

سپس با جابجایی عدد (32) یک نقطه به راست، آن مقدار از یک مقدار امضا شده با VLQ تبدیل می‌شود.

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

بنابراین ما آن را داریم: به این ترتیب است که شما 1 را به 16 تبدیل می کنید. ممکن است این فرآیند بسیار پیچیده به نظر برسد، اما زمانی که اعداد شروع به بزرگ شدن کنند، منطقی تر می شود.

مشکلات احتمالی XSSI

این مشخصات به مشکلات گنجاندن اسکریپت متقابل سایتی اشاره می کند که می تواند از مصرف نقشه منبع ناشی شود. برای کاهش این موضوع، توصیه می‌شود که خط اول نقشه منبع خود را با " )]} " قرار دهید تا عمدا جاوا اسکریپت را باطل کنید تا یک خطای نحوی ایجاد شود. ابزارهای توسعه دهنده WebKit می توانند از قبل این کار را انجام دهند.

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

همانطور که در بالا نشان داده شده است، سه کاراکتر اول برش داده می شوند تا بررسی شود که آیا با خطای نحوی در مشخصات مطابقت دارند یا خیر و در این صورت همه کاراکترهای منتهی به اولین موجودیت خط جدید (\n) حذف می شوند.

sourceURL و displayName در عمل: توابع Eval و ناشناس

در حالی که بخشی از مشخصات نقشه منبع نیست، دو قرارداد زیر به شما این امکان را می‌دهند که هنگام کار با عملکردهای ناشناس و ارزیابی‌ها، توسعه را بسیار آسان‌تر کنید.

اولین کمک کننده بسیار شبیه به ویژگی //# sourceMappingURL است و در واقع در مشخصات نقشه منبع V3 ذکر شده است. با قرار دادن کامنت ویژه زیر در کد خود، که ارزیابی خواهد شد، می توانید evals را نامگذاری کنید تا به عنوان نام های منطقی تری در ابزار توسعه دهنده شما ظاهر شوند. با استفاده از کامپایلر CoffeeScript یک نسخه ی نمایشی ساده را بررسی کنید:

نسخه ی نمایشی: کد eval() 'd را به عنوان یک اسکریپت از طریق 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) نشان داده می شود. با این حال displayName تقریباً در آب نیست و وارد کروم نخواهد شد. اما همه امیدها از بین نمی رود و پیشنهاد بسیار بهتری به نام debugName پیشنهاد شده است.

از زمان نوشتن نام eval فقط در مرورگرهای Firefox و WebKit موجود است. ویژگی displayName فقط در شب‌های WebKit وجود دارد.

بیایید با هم تجمع کنیم

در حال حاضر بحث بسیار طولانی در مورد پشتیبانی از نقشه منبع که به CoffeeScript اضافه شده است وجود دارد. بروید مشکل را بررسی کنید و پشتیبانی خود را برای اضافه شدن تولید نقشه منبع به کامپایلر CoffeeScript اضافه کنید. این یک پیروزی بزرگ برای CoffeeScript و پیروان فداکار آن خواهد بود.

UglifyJS همچنین یک مشکل نقشه منبع دارد که باید به آن نیز نگاهی بیندازید.

بسیاری از ابزارها نقشه های منبع را تولید می کنند، از جمله کامپایلر قهوه اسکریپت. من این را اکنون یک موضوع بحث برانگیز می دانم.

هرچه ابزارهای بیشتری در دسترس ما باشد که بتواند نقشه های منبع را تولید کند، وضعیت بهتری خواهیم داشت، بنابراین بروید و درخواست کنید یا پشتیبانی از نقشه منبع را به پروژه منبع باز مورد علاقه خود اضافه کنید.

این کامل نیست

یکی از مواردی که نقشه های منبع در حال حاضر به آن توجه نمی کنند عبارت های ساعت است. مشکل این است که تلاش برای بازرسی یک آرگومان یا نام متغیر در چارچوب اجرای فعلی، چیزی را باز نمی‌گرداند زیرا واقعاً وجود ندارد. این به نوعی نقشه برداری معکوس نیاز دارد تا نام واقعی آرگومان/متغیری را که می خواهید بررسی کنید در مقایسه با نام آرگومان/متغیر واقعی در جاوا اسکریپت کامپایل شده خود جستجو کنید.

البته این یک مشکل قابل حل است و با توجه بیشتر به نقشه های منبع می توانیم ویژگی های شگفت انگیز و پایداری بهتری را مشاهده کنیم.

مسائل

اخیراً jQuery 1.9 پشتیبانی از نقشه های منبع را هنگامی که از CDN های رسمی ارائه می شود، اضافه کرده است. همچنین هنگام استفاده از نظرات کامپایل شرطی IE (//@cc_on) قبل از بارگیری jQuery، باگ عجیبی را نشان داد. از آن زمان تعهدی برای کاهش این موضوع با قرار دادن sourceMappingURL در یک نظر چند خطی وجود داشته است. درسی که باید یاد گرفت از نظر شرطی استفاده نکنید.

این از آن زمان با تغییر نحو به //# پرداخته شده است .

ابزار و منابع

در اینجا منابع و ابزارهای دیگری وجود دارد که باید آنها را بررسی کنید:

  • نیک فیتزجرالد دارای فورک UglifyJS با پشتیبانی از نقشه منبع است
  • پل آیریش یک نسخه ی نمایشی کوچک دارد که نقشه های منبع را نشان می دهد
  • مجموعه تغییرات WebKit مربوط به زمانی که این حذف شد را بررسی کنید
  • این تغییرات همچنین شامل یک آزمایش طرح‌بندی بود که کل این مقاله را شروع کرد
  • موزیلا یک اشکال دارد که باید در مورد وضعیت نقشه های منبع در کنسول داخلی دنبال کنید
  • کنراد ایروین یک گوهر نقشه منبع فوق العاده مفید برای همه شما کاربران روبی نوشته است
  • مطالعه بیشتر در مورد نامگذاری eval و ویژگی displayName
  • می توانید منبع Closure Compilers را برای ایجاد نقشه های منبع بررسی کنید
  • برخی از تصاویر و صحبت در مورد پشتیبانی از نقشه های منبع GWT وجود دارد

نقشه های منبع یک ابزار بسیار قدرتمند در مجموعه ابزار توسعه دهندگان هستند. بسیار مفید است که بتوانید برنامه وب خود را نازک نگه دارید اما به راحتی قابل رفع اشکال باشد. همچنین یک ابزار یادگیری بسیار قدرتمند برای توسعه دهندگان جدیدتر است تا ببینند توسعه دهندگان باتجربه چگونه برنامه های خود را ساختار می دهند و می نویسند بدون اینکه نیازی به گذر از کدهای کوچک شده ناخوانا داشته باشند.

منتظر چی هستی؟ اکنون شروع به تولید نقشه های منبع برای همه پروژه ها کنید!