ব্লগে ফিরে যান

আপনার অ্যানালিটিক্স স্ক্রিপ্ট সম্ভবত Back/Forward Cache বন্ধ করে দিচ্ছে

back/forward cache ব্যাক-বাটন নেভিগেশনকে প্রায়-তাৎক্ষণিক করে তোলে, কিন্তু একটিমাত্র unload listener গোটা পেজের জন্য এটি বন্ধ করে দেয়। ট্র্যাকিং স্ক্রিপ্টই সাধারণত দায়ী — আর CrUX এখন সেই ক্ষতি পরিমাপ করে।

ওয়েবে সবচেয়ে দ্রুততম নেভিগেশন হলো সেটাই যেখানে কিছুই লোড হয় না। back/forward cache (bfcache) ঠিক সেটাই দেয় — আর আপনার অ্যানালিটিক্স ভেন্ডরের স্ক্রিপ্টের একটিমাত্র লাইন আপনার সাইটের প্রতিটি পেজের জন্য এটিকে বন্ধ করে দিতে পারে।

bfcache হলো একটি ব্রাউজার অপটিমাইজেশন যা ব্যবহারকারী যখন অন্য পেজে চলে যায়, তখন সেই পেজের একটি সম্পূর্ণ in-memory snapshot — JavaScript heap সহ — রেখে দেয়। ব্যাক বাটন চাপলে ব্রাউজার সেই snapshot পুনরুদ্ধার করে এবং এক্সিকিউশন আবার চালু করে, কোনো নেটওয়ার্ক রিকোয়েস্ট ছাড়াই প্রায়-তাৎক্ষণিক একটি লোড তৈরি করে। ব্যাক ও ফরোয়ার্ড নেভিগেশন আনুমানিক সব নেভিগেশনের ১০–২০% জুড়ে থাকে, তাই এটি কোনো প্রান্তিক ঘটনা নয়।

একটি Listener গোটা পেজকে অযোগ্য করে দেয়

bfcache-এর যোগ্যতা নকশাগতভাবেই ভঙ্গুর। যে পেজ একটি unload ইভেন্ট listener রেজিস্টার করেছে, ব্রাউজার সেটিকে freeze করবে না, কারণ unload ইঙ্গিত দেয় যে পেজটি ধ্বংস হওয়ার প্রত্যাশা করছে। ডেস্কটপে, Chrome ও Firefox যেকোনো unload listener-যুক্ত পেজকে bfcache-এর জন্য অযোগ্য করে দেয় — কোনো ব্যতিক্রম নেই, কোনো আংশিক ছাড় নেই।

listener-টি আপনার নিজের হতে হবে এমন কোনো কথা নেই। আপনার পেজের ভেতর থেকে, এমনকি একটি subframe-এর ভেতর থেকে unload রেজিস্টার করা third-party স্ক্রিপ্টও top-level ডকুমেন্টকে অযোগ্য করে দেয়। Lighthouse একটি নিবেদিত no-unload-listeners audit সরবরাহ করে ঠিক এই কারণেই যে দোষী কোডটি প্রায়ই এমন কোড যা সাইটের লেখক কখনো লেখেননি।

beforeunload আধুনিক ব্রাউজারে আর অযোগ্যকারী নয়, কিন্তু এটি অনির্ভরযোগ্য এবং ব্যবহারকারীর কাছে কোনো অসংরক্ষিত পরিবর্তন না থাকলে এটি এড়িয়ে যাওয়াই উত্তম।

ট্র্যাকিং স্ক্রিপ্টই সাধারণত দায়ী

unload ইভেন্ট হলো একটি চূড়ান্ত beacon পাঠানোর ক্লাসিক জায়গা — একটি সেশন flush করা, একটি "page closed" ইভেন্ট পাঠানো — তাই আচরণ-ট্র্যাকিং ও বিজ্ঞাপন স্ক্রিপ্ট অবিরত এটির দিকে হাত বাড়ায়।

Facebook-এর fbevents.js একটি unload handler রেজিস্টার করে এবং HTTP Archive অনুযায়ী এটি মোটামুটি সব ওয়েব পেজের ৯%-এ দেখা যায়। PayPal-এর tag একটি iframe ইনজেক্ট করে যা একটি unload ইভেন্ট যোগ করে, অনেক চেকআউট ফ্লোতে bfcache ব্লক করে দেয়। hCaptcha-র মতো subframe স্ক্রিপ্টও একই কাজ করেছে। এদের কোনোটির জন্যই আপনার ক্ষতি শুরু হতে আপনার নিজের কোডে পরিবর্তনের দরকার নেই — একজন ভেন্ডরের একটি আপডেট পুশ করাই যথেষ্ট।

CrUX এখন আপনাকে বিলটি দেখায়

ফিল্ড ডেটায় এটি আগে অদৃশ্য ছিল। মার্চ ২০২৪ ডেটাসেট থেকে, Chrome User Experience Report (CrUX) একটি navigation_types বিভাজন রিপোর্ট করে — যার মধ্যে back/forward cache থেকে পরিবেশিত ভিজিটের অংশ অন্তর্ভুক্ত — যাতে আপনি দেখতে পারেন কতজন বাস্তব ব্যবহারকারী তাৎক্ষণিক পথটি হারাচ্ছেন।

সম্পর্কটি প্রকট। CrUX বিশ্লেষণে একটি উচ্চ back_forward_cache অংশ এবং instant_lcp_density — অর্থাৎ ২০০ ms-এর কম LCP-যুক্ত লোডের অংশ — এর মধ্যে একটি শক্তিশালী পরিসংখ্যানগত সম্পর্ক (ρ=0.87) পাওয়া গেছে। Google-এর মার্চ ২০২৬ আপডেট LCP, INP, ও CLS-এর র‍্যাঙ্কিং ওজন বাড়ানোর পর, একটি নিজের ডেকে আনা bfcache ব্লক ৭৫তম পার্সেন্টাইলে একটি পরিমাপযোগ্য অসুবিধা, কোনো রাউন্ডিং ত্রুটি নয়।

এটি শনাক্ত ও সমাধান করা

DevTools খুলুন, Application → Back/forward cache-এ যান, এবং Run Test-এ ক্লিক করুন। Chrome প্রতিটি ব্লক করার কারণ তালিকাভুক্ত করে, third-party দ্বারা যোগ করা unload handler সহ।

আপনার নিজের কোডে bfcache restore শনাক্ত করতে, কখনো unload ব্যবহার করবেন না। pageshow ব্যবহার করুন এবং persisted যাচাই করুন:

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    // restored from bfcache — no fresh page load fired
  }
})

third-party-কে আপনাকে অযোগ্য করা থেকে থামাতে, একটি response header সেট করুন যা unload listener সম্পূর্ণরূপে নিষিদ্ধ করে:

Permissions-Policy: unload=()

এটি যেকোনো স্ক্রিপ্ট থেকে আসা unload handler নিষ্ক্রিয় করে দেয় — ভেন্ডর tag, এক্সটেনশন, বা আপনার নিজের পুরোনো কোড — তাই যা-ই লোড হোক না কেন পেজটি bfcache-এর জন্য যোগ্য থাকে।

যে ট্র্যাকার এটিকে কখনো স্পর্শ করে না

কাঠামোগত সমাধান হলো এমন instrumentation ব্যবহার করা যার প্রথমেই unload-এর জন্য listen করার কোনো কারণ নেই। একটি privacy-first ট্র্যাকার একটিমাত্র keepalive রিকোয়েস্ট দিয়ে একটি pageview রেকর্ড করে এবং রিকোয়েস্টটিকে নিজে থেকেই পেজের চেয়ে বেশি সময় টিকে থাকতে দেয় — কোনো teardown beacon নেই, কোনো unload handler নেই, ব্রাউজারের flag করার মতো কিছুই নেই:

fetch('/collect', {
  method: 'POST',
  keepalive: true,
  body: JSON.stringify({ site_id, path: location.pathname })
})

একটি ট্র্যাকারের যখন একটি পেজ background-এ চলে যাওয়ার প্রতিক্রিয়া জানানো দরকার হয়, তখন সঠিক সংকেত হলো visibilitychange বা pagehide, যেগুলো পেজটিকে bfcache-অযোগ্য না করেই fire হয়। Monoid-এর ট্র্যাকার মোটামুটি ২ KB, কোনো cookie সেট করে না, এবং পেজ লাইফসাইকেলের পরিবর্তে SPA রুট পরিবর্তনের জন্য history.pushState hook করে — তাই এর রেজিস্টার করার মতো কোনো unload listener নেই এবং আপনার back/forward cache বন্ধ করার মতো কিছুই নেই।

নজরদারি অ্যানালিটিক্স পারফরম্যান্সের ওপর এমনভাবে কর বসায় যা একটি ল্যাব রানে দেখা যায় না। একটি bfcache ব্লক হলো সবচেয়ে নীরব ক্ষতিগুলোর একটি: কোনো error নেই, কোনো ধীর render নেই, শুধু একটি ব্যাক বাটন যা memory থেকে restore করার কথা থাকলেও নেটওয়ার্ক থেকে রিলোড করে।

সূত্র

Comments

Loading comments…