সার্ভিস ওয়ার্কারের মাধ্যমে ব্যাকগ্রাউন্ড বা ইভেন্ট পৃষ্ঠা পরিবর্তন করা
ব্যাকগ্রাউন্ড কোড যাতে মূল থ্রেড থেকে দূরে থাকে তা নিশ্চিত করতে, সার্ভিস ওয়ার্কার এক্সটেনশনের ব্যাকগ্রাউন্ড বা ইভেন্ট পৃষ্ঠা পরিবর্তন করে। এটি এক্সটেনশনকে শুধুমাত্র প্রয়োজন হলেই চালানোর অনুমতি দেয়, যার ফলে রিসোর্স সাশ্রয় হয়।
এক্সটেনশন চালু হওয়ার পর থেকে ব্যাকগ্রাউন্ড পৃষ্ঠাগুলি এক্সটেনশনের একটি মৌলিক উপাদান হিসেবে কাজ করছে। সহজ কথায়, ব্যাকগ্রাউন্ড পৃষ্ঠা এমন একটি পরিবেশ প্রদান করে যা অন্য কোনও উইন্ডো বা ট্যাবের উপর নির্ভর করে না। এটি এক্সটেনশনকে ইভেন্টের প্রতিক্রিয়া হিসেবে পর্যবেক্ষণ ও কাজ করার অনুমতি দেয়।
এই পৃষ্ঠায় ব্যাকগ্রাউন্ড পৃষ্ঠা থেকে এক্সটেনশন সার্ভিস ওয়ার্কারে কনভার্ট করার টাস্কের বিবরণ দেওয়া আছে। সাধারণত এক্সটেনশন সার্ভিস ওয়ার্কার সম্পর্কে আরও তথ্যের জন্য, সার্ভিস ওয়ার্কারের মাধ্যমে ইভেন্ট ম্যানেজ করুন টিউটোরিয়াল এবং এক্সটেনশন সার্ভিস ওয়ার্কার সম্পর্কে বিভাগ দেখুন।
ব্যাকগ্রাউন্ড স্ক্রিপ্ট ও এক্সটেনশন সার্ভিস ওয়ার্কারের মধ্যে পার্থক্য
কিছু ক্ষেত্রে আপনি এক্সটেনশন সার্ভিস ওয়ার্কারদের 'ব্যাকগ্রাউন্ড স্ক্রিপ্ট' হিসেবে দেখতে পাবেন। যদিও এক্সটেনশন সার্ভিস ওয়ার্কার ব্যাকগ্রাউন্ডে রান করে, তাদের ব্যাকগ্রাউন্ড স্ক্রিপ্ট বলা কিছুটা বিভ্রান্তিকর কারণ এটি একই ধরনের ক্ষমতার ইঙ্গিত দেয়। পার্থক্যগুলি নিচে বর্ণনা করা হয়েছে।
ব্যাকগ্রাউন্ড পৃষ্ঠা থেকে পরিবর্তন
ব্যাকগ্রাউন্ড পৃষ্ঠার সাথে সার্ভিস ওয়ার্কারের অনেক পার্থক্য আছে।
- এগুলি মূল থ্রেডের বাইরে কাজ করে, যার অর্থ হল এগুলি এক্সটেনশন কন্টেন্টে হস্তক্ষেপ করে না।
- এগুলির বিশেষ ক্ষমতা আছে, যেমন এক্সটেনশনের অরিজিনে ফেচ ইভেন্ট ইন্টারসেপ্ট করা, যেমন টুলবার পপ-আপ থেকে আসা ইভেন্ট।
- তারা ক্লায়েন্ট ইন্টারফেস-এর মাধ্যমে অন্যান্য কনটেক্সটের সাথে যোগাযোগ ও ইন্টার্যাক্ট করতে পারে।
আপনাকে যেসব পরিবর্তন করতে হবে
ব্যাকগ্রাউন্ড স্ক্রিপ্ট ও সার্ভিস ওয়ার্কারের কাজ করার পদ্ধতির মধ্যে পার্থক্য বিবেচনা করে আপনাকে কোডে কিছু পরিবর্তন করতে হবে। শুরুতে, ম্যানিফেস্ট ফাইলে যেভাবে সার্ভিস ওয়ার্কার নির্দিষ্ট করা হয়, ব্যাকগ্রাউন্ড স্ক্রিপ্ট নির্দিষ্ট করার পদ্ধতি তার থেকে আলাদা। এসব ছাড়াও:
- যেহেতু তারা DOM বা
windowইন্টারফেস অ্যাক্সেস করতে পারে না, তাই আপনাকে এই ধরনের কল অন্য API বা অফস্ক্রিন ডকুমেন্টে সরাতে হবে। - রিটার্ন করা প্রমিজের উত্তরে বা ইভেন্ট কলব্যাকের মধ্যে ইভেন্ট লিসনার রেজিস্টার করা উচিত নয়।
- যেহেতু সেগুলি
XMLHttpRequest()-এর সাথে ব্যাকওয়ার্ড কম্প্যাটিবল নয়, তাই আপনাকে এই ইন্টারফেসে কল করার পরিবর্তেfetch()-এ কল করতে হবে। - ব্যবহার না করা হলে যেহেতু এগুলি বন্ধ হয়ে যায়, তাই গ্লোবাল ভেরিয়েবেলের উপর নির্ভর না করে আপনাকে অ্যাপ্লিকেশন স্টেট বজায় রাখতে হবে। সার্ভিস ওয়ার্কার বন্ধ করে দিলে, টাইমার সম্পূর্ণ হওয়ার আগেই বন্ধ হয়ে যেতে পারে। আপনাকে এগুলি অ্যালার্ম দিয়ে পরিবর্তন করতে হবে।
এই পৃষ্ঠায় এইসব টাস্কের ব্যাপারে বিস্তারিত বিবরণ দেওয়া আছে।
ম্যানিফেস্টে "ব্যাকগ্রাউন্ড" ফিল্ড আপডেট করুন
Manifest V3-তে, ব্যাকগ্রাউন্ড পৃষ্ঠা সার্ভিস ওয়ার্কার দ্বারা পরিবর্তন করা হয়। ম্যানিফেস্টে করা পরিবর্তনগুলি নিচে তালিকাভুক্ত করা হয়েছে।
manifest.json-এ"background.scripts"-এর জায়গায়"background.service_worker"নামটি ব্যবহার করুন। মনে রাখবেন,"service_worker"ফিল্ডে স্ট্রিংয়ের অ্যারে নয়, স্ট্রিং ব্যবহার করা হয়।manifest.jsonথেকে"background.persistent"সরান।
{ ... "background": { "scripts": [ "backgroundContextMenus.js", "backgroundOauth.js" ], "persistent": false }, ... }
{ ... "background": { "service_worker": "service_worker.js", "type": "module" } ... }
"service_worker" ফিল্ডে একটি স্ট্রিং থাকে। আপনি ES মডিউল (import কীওয়ার্ড ব্যবহার করে) ব্যবহার করলে, তবেই আপনার "type" ফিল্ডের প্রয়োজন হবে। এর ভ্যালু সবসময় "module" হবে। আরও তথ্যের জন্য, এক্সটেনশন সার্ভিস ওয়ার্কারের প্রাথমিক তথ্য দেখুন
DOM এবং উইন্ডো কল অফস্ক্রিন ডকুমেন্টে সরান
কিছু এক্সটেনশনের ক্ষেত্রে, দৃশ্যত নতুন উইন্ডো বা ট্যাব না খুলেই DOM এবং উইন্ডো অবজেক্টে অ্যাক্সেস প্রয়োজন হয়। Offscreen API ব্যবহারকারীর অভিজ্ঞতা ব্যাহত না করে, এক্সটেনশনের সাথে প্যাকেজ করা অপ্রদর্শিত ডকুমেন্ট খোলা ও বন্ধ করার মাধ্যমে এইসব ব্যবহারের ক্ষেত্রে সহায়তা করে। মেসেজ পাসিং ছাড়া, অফস্ক্রিন ডকুমেন্ট অন্যান্য এক্সটেনশন কনটেক্সটের সাথে API শেয়ার করে না, তবে এক্সটেনশনের সাথে ইন্টার্যাক্ট করার জন্য সম্পূর্ণ ওয়েব পেজ হিসেবে কাজ করে।
Offscreen API ব্যবহার করতে, সার্ভিস ওয়ার্কার থেকে অফস্ক্রিন ডকুমেন্ট তৈরি করুন।
browser.offscreen.createDocument({
url: browser.runtime.getURL('offscreen.html'),
reasons: ['CLIPBOARD'],
justification: 'testing the offscreen API',
});
অফস্ক্রিন ডকুমেন্টে এমন যেকোনও অ্যাকশন পারফর্ম করুন যা আপনি আগে ব্যাকগ্রাউন্ড স্ক্রিপ্টে রান করতেন। যেমন, আপনি হোস্ট পৃষ্ঠায় বেছে নেওয়া টেক্সট কপি করতে পারেন।
let textEl = document.querySelector('#text');
textEl.value = data;
textEl.select();
document.execCommand('copy');
মেসেজ পাসিং ব্যবহার করে অফস্ক্রিন ডকুমেন্ট ও এক্সটেনশন সার্ভিস ওয়ার্কারের মধ্যে যোগাযোগ করুন।
localStorage অন্য কোনও প্রকারে কনভার্ট করুন
ওয়েব প্ল্যাটফর্মের Storage ইন্টারফেস (window.localStorage থেকে অ্যাক্সেস করা যায়) কোনও সার্ভিস ওয়ার্কারে ব্যবহার করা যাবে না। এই সমস্যার সমাধান করতে, দুটি কাজের মধ্যে একটি করুন। প্রথমে, আপনি অন্য স্টোরেজ মেকানিজমে কল করে এটি পরিবর্তন করতে পারেন। browser.storage.local নেমস্পেস বেশিরভাগ ব্যবহারের ক্ষেত্রে কাজ করবে, তবে অন্যান্য বিকল্প উপলভ্য আছে।
এছাড়াও, আপনি এর কল অফস্ক্রিন ডকুমেন্টে সরাতে পারবেন। যেমন, localStorage-এ আগে থেকে স্টোর করা ডেটা অন্য মেকানিজমে মাইগ্রেট করতে:
- কনভার্সন রুটিন ও
runtime.onMessageহ্যান্ডলার সহ অফস্ক্রিন ডকুমেন্ট তৈরি করুন। - অফস্ক্রিন ডকুমেন্টে কনভার্সন রুটিন যোগ করুন।
- এক্সটেনশন সার্ভিস ওয়ার্কারে আপনার ডেটার জন্য
browser.storageচেক করুন। - আপনার ডেটা খুঁজে পাওয়া না গেলে, অফস্ক্রিন ডকুমেন্ট তৈরি করুন এবং কনভার্সন রুটিন শুরু করতে
runtime.sendMessage()কল করুন। - অফস্ক্রিন ডকুমেন্টে আপনি যে
runtime.onMessageহ্যান্ডলার যোগ করেছেন, সেখানে কনভার্সন রুটিন কল করুন।
এছাড়াও, এক্সটেনশনে ওয়েব স্টোরেজ API কীভাবে কাজ করে সেই বিষয়ে কিছু সূক্ষ্ম পার্থক্য আছে। স্টোরেজ ও কুকি থেকে আরও জানুন।
সিঙ্ক্রোনাসভাবে লিসনার রেজিস্টার করুন
Manifest V3-তে অ্যাসিঙ্ক্রোনাসভাবে (যেমন, প্রমিস বা কলব্যাকের মধ্যে) লিসেনার রেজিস্টার করলে তা কাজ করবেই এমন কোনও গ্যারেন্টি নেই। নিম্নলিখিত কোডটি বিবেচনা করুন।
browser.storage.local.get(["badgeText"], ({ badgeText }) => {
browser.browserAction.setBadgeText({ text: badgeText });
browser.browserAction.onClicked.addListener(handleActionClick);
});
এটি একটি পারসিস্টেন্ট ব্যাকগ্রাউন্ড পৃষ্ঠার সাথে কাজ করে কারণ পৃষ্ঠাটি ক্রমাগত চলছে এবং কখনও পুনরায় শুরু করা হয় না। Manifest V3-এ, ইভেন্ট ডিসপ্যাচ করা হলে সার্ভিস ওয়ার্কার আবার শুরু করা হবে। এর অর্থ হল, ইভেন্ট শুরু হলে, লিসনার রেজিস্টার করা হবে না (কারণ সেগুলি অ্যাসিঙ্ক্রোনাসভাবে যোগ করা হয়) এবং ইভেন্টটি মিস হয়ে যাবে।
পরিবর্তে, আপনার স্ক্রিপ্টের সবথেকে উপরের লেভেলে ইভেন্ট লিসেনার রেজিস্ট্রেশন সরান। এটি নিশ্চিত করে যে Chrome অবিলম্বে আপনার অ্যাকশনের ক্লিক হ্যান্ডলার খুঁজে পেতে এবং চালু করতে পারবে, এমনকি আপনার এক্সটেনশন তার স্টার্টআপ লজিক কার্যকর করা শেষ না করলেও।
browser.action.onClicked.addListener(handleActionClick);
browser.storage.local.get(["badgeText"], ({ badgeText }) => {
browser.action.setBadgeText({ text: badgeText });
});
XMLHttpRequest() গ্লোবাল fetch() দিয়ে প্রতিস্থাপন করুন
সার্ভিস ওয়ার্কার, এক্সটেনশন বা অন্য কোনও উপায়ে XMLHttpRequest() কল করা যাবে না। আপনার ব্যাকগ্রাউন্ড স্ক্রিপ্ট থেকে XMLHttpRequest()-এ করা কল গ্লোবাল fetch()-এ করা কলের মাধ্যমে পরিবর্তন করুন।
const xhr = new XMLHttpRequest(); console.log('UNSENT', xhr.readyState); xhr.open('GET', '/api', true); console.log('OPENED', xhr.readyState); xhr.onload = () => { console.log('DONE', xhr.readyState); }; xhr.send(null);
const response = await fetch('https://www.example.com/greeting.json'') console.log(response.statusText);
স্টেট বজায় রাখুন
সার্ভিস ওয়ার্কার ক্ষণস্থায়ী, যার অর্থ হল, ব্যবহারকারীর ব্রাউজার সেশন চলাকালীন এটি বারবার শুরু, রান ও বন্ধ হতে পারে। এর অর্থ হল, পূর্ববর্তী প্রসঙ্গটি মুছে ফেলার কারণে গ্লোবাল ভেরিয়েবেলে ডেটা অবিলম্বে উপলভ্য হয় না। এই সমস্যা এড়াতে, স্টোরেজ API-কে সোর্স অফ ট্রুথ হিসেবে ব্যবহার করুন। এটি কীভাবে করতে হয় তা একটি উদাহরণের মাধ্যমে দেখানো হবে।
নিম্নলিখিত উদাহরণে নাম স্টোর করার জন্য গ্লোবাল ভেরিয়েবেল ব্যবহার করা হয়েছে। কোনও সার্ভিস ওয়ার্কারে, ব্যবহারকারীর ব্রাউজার সেশন চলাকালীন এই ভেরিয়েবল একাধিকবার রিসেট করা হতে পারে।
let savedName = undefined; browser.runtime.onMessage.addListener(({ type, name }) => { if (type === "set-name") { savedName = name; } }); browser.browserAction.onClicked.addListener((tab) => { browser.tabs.sendMessage(tab.id, { name: savedName }); });
Manifest V3-এর জন্য, গ্লোবাল ভেরিয়েবেলকে Storage API-তে কল দিয়ে প্রতিস্থাপন করুন।
browser.runtime.onMessage.addListener(({ type, name }) => { if (type === "set-name") { browser.storage.local.set({ name }); } }); browser.action.onClicked.addListener(async (tab) => { const { name } = await browser.storage.local.get(["name"]); browser.tabs.sendMessage(tab.id, { name }); });
টাইমারকে অ্যালার্মে কনভার্ট করুন
setTimeout() বা setInterval() পদ্ধতি ব্যবহার করে বিলম্বিত বা পর্যায়ক্রমিক অপারেশন ব্যবহার করা সাধারণ ব্যাপার। তবে, এইসব API সার্ভিস ওয়ার্কারে কাজ নাও করতে পারে, কারণ সার্ভিস ওয়ার্কার বন্ধ হয়ে গেলে টাইমার বাতিল হয়ে যায়।
// 3 minutes in milliseconds const TIMEOUT = 3 * 60 * 1000; setTimeout(() => { browser.action.setIcon({ path: getRandomIconPath(), }); }, TIMEOUT);
পরিবর্তে, Alarms API ব্যবহার করুন। অন্যান্য লিসেনারের মতো, অ্যালার্ম লিসেনারকে আপনার স্ক্রিপ্টের টপ লেভেলে রেজিস্টার করতে হবে।
async function startAlarm(name, duration) { await browser.alarms.create(name, { delayInMinutes: 3 }); } browser.alarms.onAlarm.addListener(() => { browser.action.setIcon({ path: getRandomIconPath(), }); });
সার্ভিস ওয়ার্কার চালু রাখুন
সার্ভিস ওয়ার্কাররা সংজ্ঞা অনুযায়ী ইভেন্ট-চালিত এবং কোনও অ্যাক্টিভিটি না থাকলে বন্ধ হয়ে যাবে। এইভাবে Chrome আপনার এক্সটেনশনের পারফর্ম্যান্স ও মেমরি ব্যবহার অপ্টিমাইজ করতে পারে। আমাদের সার্ভিস ওয়ার্কার লাইফসাইকেল ডকুমেন্টেশন থেকে আরও জানুন। ব্যতিক্রমী ক্ষেত্রে, কোনও সার্ভিস ওয়ার্কার যাতে আরও বেশি সময় ধরে অ্যাক্টিভ থাকে তা নিশ্চিত করার জন্য অতিরিক্ত ব্যবস্থা নেওয়ার প্রয়োজন হতে পারে।
দীর্ঘ সময় ধরে চলা অপারেশন শেষ না হওয়া পর্যন্ত সার্ভিস ওয়ার্কারকে চালু রাখুন
দীর্ঘ সময় ধরে চলা সার্ভিস ওয়ার্কার অপারেশন যা এক্সটেনশন API কল করে না, সেই সময় সার্ভিস ওয়ার্কার অপারেশন চলাকালীন বন্ধ হয়ে যেতে পারে। উদাহরণের মধ্যে অন্তর্ভুক্ত রয়েছে:
fetch()অনুরোধ সম্ভবত পাঁচ মিনিটের বেশি সময় নিচ্ছে (যেমন, সম্ভবত দুর্বল কানেকশনে একটি বড় ডাউনলোড)।- একটি জটিল অ্যাসিঙ্ক্রোনাস গণনা যা ৩০ সেকেন্ডের বেশি সময় নেয়।
এইসব ক্ষেত্রে সার্ভিস ওয়ার্কারের লাইফটাইম বাড়াতে, আপনি টাইমআউট কাউন্টার রিসেট করার জন্য নির্দিষ্ট সময় অন্তর একটি ট্রিভিয়াল এক্সটেনশন API কল করতে পারেন। মনে রাখবেন, এটি শুধুমাত্র ব্যতিক্রমী ক্ষেত্রে ব্যবহার করা হয় এবং বেশিরভাগ পরিস্থিতিতে একই ফলাফল পাওয়ার জন্য সাধারণত আরও ভালো, প্ল্যাটফর্ম ইডিওমেটিক উপায় থাকে।
নিম্নলিখিত উদাহরণে একটি waitUntil() হেল্পার ফাংশন দেখানো হয়েছে যা কোনও নির্দিষ্ট প্রমিস সমাধান না হওয়া পর্যন্ত আপনার সার্ভিস ওয়ার্কারকে চালু রাখে:
async function waitUntil(promise) {
const keepAlive = setInterval(browser.runtime.getPlatformInfo, 25 * 1000);
try {
await promise;
} finally {
clearInterval(keepAlive);
}
}
waitUntil(someExpensiveCalculation());
সার্ভিস ওয়ার্কারকে একটানা চালু রাখুন
খুব কম ক্ষেত্রে, লাইফটাইম অনির্দিষ্টকালের জন্য বাড়ানো প্রয়োজন হয়। আমরা এন্টারপ্রাইজ এবং শিক্ষাকে সবচেয়ে বড় ব্যবহারের ক্ষেত্র হিসেবে চিহ্নিত করেছি এবং আমরা বিশেষভাবে সেখানে এটির অনুমতি দিই, তবে আমরা সাধারণত এটি সমর্থন করি না। এইসব ব্যতিক্রমী পরিস্থিতিতে, একটি তুচ্ছ এক্সটেনশন API-কে পর্যায়ক্রমে কল করার মাধ্যমে একটি সার্ভিস ওয়ার্কারকে জীবিত রাখা যেতে পারে। মনে রাখবেন, এই সাজেশন শুধুমাত্র এন্টারপ্রাইজ বা শিক্ষা প্রতিষ্ঠানের জন্য ম্যানেজ করা ডিভাইসে চলা এক্সটেনশনের ক্ষেত্রে প্রযোজ্য। অন্যান্য ক্ষেত্রে এটি অনুমোদিত নয় এবং Chrome এক্সটেনশন টিমের কাছে ভবিষ্যতে সেইসব এক্সটেনশনের বিরুদ্ধে ব্যবস্থা নেওয়ার অধিকার আছে।
আপনার সার্ভিস ওয়ার্কারকে চালু রাখতে নিম্নলিখিত কোড স্নিপেট ব্যবহার করুন:
/**
* Tracks when a service worker was last alive and extends the service worker
* lifetime by writing the current time to extension storage every 20 seconds.
* You should still prepare for unexpected termination - for example, if the
* extension process crashes or your extension is manually stopped at
* chrome://serviceworker-internals.
*/
let heartbeatInterval;
async function runHeartbeat() {
await browser.storage.local.set({ 'last-heartbeat': new Date().getTime() });
}
/**
* Starts the heartbeat interval which keeps the service worker alive. Call
* this sparingly when you are doing work which requires persistence, and call
* stopHeartbeat once that work is complete.
*/
async function startHeartbeat() {
// Run the heartbeat once at service worker startup.
runHeartbeat().then(() => {
// Then again every 20 seconds.
heartbeatInterval = setInterval(runHeartbeat, 20 * 1000);
});
}
async function stopHeartbeat() {
clearInterval(heartbeatInterval);
}
/**
* Returns the last heartbeat stored in extension storage, or undefined if
* the heartbeat has never run before.
*/
async function getLastHeartbeat() {
return (await browser.storage.local.get('last-heartbeat'))['last-heartbeat'];
}