Source Map چیست و چرا بدون آن خطای production بی‌فایده است

Source Map چیست و چرا بدون آن خطای production بی‌فایده است
در این مقاله می‌خوانید
  1. چرا کد production این شکلی است
  2. Source Map چه می‌کند
  3. چطور تولیدش کنیم
  4. داخلش چه خبر است
  5. آپلود خودکار هنگام انتشار
  6. سؤال امنیتی: آیا کد ما لو می‌رود؟
  7. اشتباهات رایجی که نقشه را بی‌اثر می‌کنند
  8. چطور مطمئن شویم کار می‌کند
  9. جمع‌بندی
  10. منابع و مطالعهٔ بیشتر

سیستم رصد خطا راه انداخته‌اید، خطاها دارند می‌آیند، و اولین موردی که باز می‌کنید این است:

TypeError: Cannot read properties of undefined
    at t (main.4f8a2c.js:1:24817)
    at n (main.4f8a2c.js:1:18402)

تابعی به نام t در خط ۱، ستون ۲۴۸۱۷. این هیچ اطلاعاتی به شما نمی‌دهد. تمام سرمایه‌گذاری‌تان روی رصد خطا، بدون یک قطعهٔ گمشده، تقریباً بی‌ارزش است — و آن قطعه Source Map است.

چرا کد production این شکلی است

کدی که برای کاربران فرستاده می‌شود، همان کدی نیست که نوشته‌اید. ابزار build چند کار روی آن انجام می‌دهد: نام متغیرها و توابع را به یک و دو حرفی کوتاه می‌کند، فاصله‌ها و توضیحات را حذف می‌کند، ده‌ها فایل را در یکی ادغام می‌کند، و کد مدرن را به نسخهٔ سازگارتر تبدیل می‌کند.

نتیجه فایلی است که شاید یک‌سوم حجم اصلی باشد و کاربر سریع‌تر دریافتش کند — ولی برای انسان کاملاً ناخواناست. تابع calculateDiscount شما حالا t نام دارد.

Source Map چه می‌کند

Source Map یک فایل JSON است که نقشهٔ برگشت را نگه می‌دارد: موقعیت فلان در فایل فشرده، معادل فلان خط و ستون در کدام فایل اصلی است، و نام اصلی آن متغیر این بوده.

وقتی این نقشه در اختیار ابزار باشد، همان stack trace بالا تبدیل می‌شود به:

TypeError: Cannot read properties of undefined
    at calculateDiscount (src/checkout/pricing.js:42:18)
    at CheckoutPage (src/pages/Checkout.jsx:87:5)

همان خطا، همان داده — ولی حالا می‌دانید کجا را نگاه کنید.

چطور تولیدش کنیم

در بیشتر ابزارهای امروزی فقط یک تنظیم است. نمونه برای Vite:

// vite.config.js
export default { build: { sourcemap: true } };

و برای webpack:

module.exports = { mode: 'production', devtool: 'source-map' };

خروجی، فایل‌هایی با پسوند .js.map کنار فایل‌های اصلی است، و در انتهای هر فایل جاوااسکریپت خطی اضافه می‌شود که به آن اشاره می‌کند.

داخلش چه خبر است

لازم نیست فرمتش را بلد باشید، ولی دانستن یک نکته کمک می‌کند: Source Map یک نگاشت خط‌به‌خط ساده نیست. فایل JSON است با فیلدی به نام mappings که رشته‌ای فشرده از موقعیت‌هاست:

{
  "version": 3,
  "sources": ["src/checkout/pricing.js", "src/pages/Checkout.jsx"],
  "names": ["calculateDiscount", "total"],
  "mappings": "AAAA,SAASA,EAAiBC,..."
}

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

نکتهٔ عملی این توضیح: چون نگاشت بر پایهٔ موقعیت دقیق است، کوچک‌ترین تفاوتی بین فایلی که منتشر کرده‌اید و نقشه‌ای که آپلود کرده‌اید، ترجمه را کاملاً بی‌اعتبار می‌کند. این‌جا «تقریباً درست» وجود ندارد.

آپلود خودکار هنگام انتشار

رویکرد حرفه‌ای این است که نقشه‌ها در فرآیند استقرار به سرویس رصد خطا فرستاده شوند و روی سرور عمومی نمانند. الگوی کلی در هر خط لولهٔ CI:

- build کن (با sourcemap فعال)
- نقشه‌ها را با شمارهٔ نسخه به سرویس رصد آپلود کن
- فایل‌های .map را از خروجی نهایی حذف کن
- بقیه را منتشر کن

نکتهٔ کلیدی، همان شمارهٔ نسخه است. همان مقدار باید هنگام مقداردهی SDK هم فرستاده شود، تا سرویس بداند خطایی که از مرورگر کاربر آمده با کدام مجموعه نقشه باید ترجمه شود. بدون این، وقتی چند نسخه هم‌زمان در دست کاربران باشد — که به‌خاطر کش همیشه هست — ترجمه‌ها قاطی می‌شوند.

سؤال امنیتی: آیا کد ما لو می‌رود؟

این نگرانی درست است و باید جدی گرفته شود. Source Map عملاً شامل کد اصلی شماست؛ هر کسی که به آن دسترسی داشته باشد، می‌تواند کد خواناتان را بازسازی کند.

سه رویکرد وجود دارد:

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

۲. ارسال خصوصی به سرویس رصد خطا. رویکرد رایج تیم‌های حرفه‌ای: هنگام انتشار، فایل‌های نقشه را مستقیم به سرویس رصد خطا آپلود می‌کنید و روی سرور عمومی قرار نمی‌دهید. سرویس می‌تواند stack trace را ترجمه کند، ولی هیچ کاربری به نقشه دسترسی ندارد.

۳. محدود کردن دسترسی. نقشه‌ها را روی سرور بگذارید ولی دسترسی به آن‌ها را با احراز هویت یا محدودیت IP ببندید.

آنچه نباید بکنید: تولید نکردنشان. بدون نقشه، خطای production را نمی‌توانید ردیابی کنید و عملاً کور می‌مانید.

اشتباهات رایجی که نقشه را بی‌اثر می‌کنند

نقشه با نسخهٔ اشتباه. اگر کد را دوباره build کنید و نقشهٔ قدیمی بماند، ترجمه به خطوط اشتباهی اشاره می‌کند — که از نداشتن نقشه هم بدتر است، چون شما را به کد بی‌ربطی می‌فرستد. نقشه‌ها را همیشه هم‌زمان با انتشار به‌روز کنید.

نبود شناسهٔ نسخه. اگر چند نسخه هم‌زمان در دست کاربران باشد — که به‌خاطر کش همیشه هست — سرویس رصد باید بداند این خطا از کدام نسخه آمده. برای همین هنگام مقداردهی اولیهٔ SDK، نسخه یا شمارهٔ انتشار را بفرستید.

نقشه‌ای که ۴۰۴ می‌دهد. فایل‌های .map گاهی در فرآیند استقرار حذف می‌شوند یا در مسیر دیگری می‌نشینند. یک بار مستقیم در مرورگر بازشان کنید تا مطمئن شوید در دسترس‌اند.

فعال بودن در همه‌جا جز production. شایع‌ترین حالت: در محیط توسعه کار می‌کند و کسی متوجه نمی‌شود که در build نهایی خاموش است. این یکی از دلایلی است که باگ‌ها فقط در production ظاهر می‌شوند.

چطور مطمئن شویم کار می‌کند

ساده‌ترین آزمون: عمداً یک خطا در نسخهٔ production ایجاد کنید. یک دکمهٔ مخفی یا یک پارامتر در آدرس که خطایی بیندازد. بعد در داشبورد رصد خطا نگاه کنید.

اگر نام فایل و تابع درست را دیدید، همه‌چیز مرتب است. اگر main.js:1:24817 دیدید، هنوز کاری مانده — و بهتر است همین حالا حلش کنید تا وقتی که یک باگ واقعی و فوری در میان باشد.

جمع‌بندی

Source Map از آن کارهایی است که هزینه‌اش یک خط تنظیمات است و نبودش کل سرمایه‌گذاری شما روی رصد خطا را بی‌اثر می‌کند. تیمی که خطاهایش را جمع می‌کند ولی نمی‌تواند بخواندشان، فقط فهرستی از پیام‌های نامفهوم دارد. برای خانواده‌های دیگر خطا، راهنمای جامع خطاهای جاوااسکریپت را ببینید.

اگر همین حالا سیستم رصد خطا دارید، اولین کاری که باید بکنید این است: یک خطای اخیر را باز کنید و ببینید stack trace به فایل واقعی اشاره می‌کند یا به t در خط ۱.

منابع و مطالعهٔ بیشتر

باگ‌ماگ را رایگان امتحان کنید

خطاهای سایتتان را خودکار ثبت کنید و بگذارید کاربران با یک کلیک باگ گزارش دهند.

شروع رایگان