একজন সেবা কর্মীর কাছে মাইগ্রেট করুন

সার্ভিস ওয়ার্কার দিয়ে ব্যাকগ্রাউন্ড বা ইভেন্ট পেজ প্রতিস্থাপন করা

একটি সার্ভিস ওয়ার্কার এক্সটেনশনের ব্যাকগ্রাউন্ড বা ইভেন্ট পেজকে প্রতিস্থাপন করে, যাতে ব্যাকগ্রাউন্ড কোড মেইন থ্রেড থেকে দূরে থাকে। এর ফলে এক্সটেনশনগুলো কেবল প্রয়োজনের সময়ই চলে, যা রিসোর্স সাশ্রয় করে।

এক্সটেনশন চালু হওয়ার পর থেকেই ব্যাকগ্রাউন্ড পেজ এর একটি মৌলিক উপাদান হয়ে উঠেছে। সহজ কথায়, ব্যাকগ্রাউন্ড পেজ এমন একটি পরিবেশ প্রদান করে যা অন্য কোনো উইন্ডো বা ট্যাব থেকে স্বাধীনভাবে কাজ করে। এর ফলে এক্সটেনশনগুলো বিভিন্ন ঘটনা পর্যবেক্ষণ করতে এবং সে অনুযায়ী কাজ করতে পারে।

এই পৃষ্ঠায় ব্যাকগ্রাউন্ড পেজগুলোকে এক্সটেনশন সার্ভিস ওয়ার্কারে রূপান্তর করার কাজগুলো বর্ণনা করা হয়েছে। সাধারণভাবে এক্সটেনশন সার্ভিস ওয়ার্কার সম্পর্কে আরও তথ্যের জন্য, “সার্ভিস ওয়ার্কারদের দিয়ে ইভেন্ট পরিচালনা করুন” টিউটোরিয়াল এবং “এক্সটেনশন সার্ভিস ওয়ার্কার সম্পর্কে” বিভাগটি দেখুন।

পটভূমি স্ক্রিপ্ট এবং সম্প্রসারণ পরিষেবা কর্মীদের মধ্যে পার্থক্য

কিছু ক্ষেত্রে এক্সটেনশন সার্ভিস ওয়ার্কারদের 'ব্যাকগ্রাউন্ড স্ক্রিপ্ট' বলা হয়। যদিও এক্সটেনশন সার্ভিস ওয়ার্কাররা ব্যাকগ্রাউন্ডেই চলে, এদেরকে ব্যাকগ্রাউন্ড স্ক্রিপ্ট বলাটা কিছুটা বিভ্রান্তিকর, কারণ এতে একই ধরনের সক্ষমতা বোঝানো হয়। পার্থক্যগুলো নিচে বর্ণনা করা হলো।

পটভূমি পৃষ্ঠাগুলি থেকে পরিবর্তন

সার্ভিস ওয়ার্কারদের সাথে ব্যাকগ্রাউন্ড পেজগুলোর বেশ কিছু পার্থক্য রয়েছে।

  • এগুলো মূল থ্রেডের বাইরে কাজ করে, যার মানে হলো এগুলো এক্সটেনশনের বিষয়বস্তুতে হস্তক্ষেপ করে না।
  • তাদের বিশেষ ক্ষমতা রয়েছে, যেমন এক্সটেনশনের অরিজিনে ফেচ ইভেন্টগুলো ইন্টারসেপ্ট করা, যা টুলবার পপআপ থেকে আসে।
  • তারা ক্লায়েন্ট ইন্টারফেসের মাধ্যমে অন্যান্য প্রেক্ষাপটের সাথে যোগাযোগ ও মিথস্ক্রিয়া করতে পারে।

যে পরিবর্তনগুলি আপনাকে করতে হবে

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

  • যেহেতু তারা DOM বা window ইন্টারফেস অ্যাক্সেস করতে পারে না, তাই আপনাকে এই ধরনের কলগুলোকে একটি ভিন্ন API-তে অথবা একটি অফস্ক্রিন ডকুমেন্টে স্থানান্তর করতে হবে।
  • রিটার্ন করা প্রমিজের প্রতিক্রিয়ায় অথবা ইভেন্ট কলব্যাকের ভিতরে ইভেন্ট লিসেনার রেজিস্টার করা উচিত নয়।
  • যেহেতু এগুলো XMLHttpRequest() এর সাথে ব্যাকওয়ার্ড কম্প্যাটিবল নয়, তাই আপনাকে এই ইন্টারফেসের কলগুলোকে fetch() এর কল দিয়ে প্রতিস্থাপন করতে হবে।
  • যেহেতু ব্যবহার না হলে এগুলি বন্ধ হয়ে যায়, তাই গ্লোবাল ভেরিয়েবলের উপর নির্ভর না করে আপনাকে অ্যাপ্লিকেশনের অবস্থা সংরক্ষণ করতে হবে। বন্ধ হয়ে যাওয়া সার্ভিস ওয়ার্কারগুলি টাইমার সম্পূর্ণ হওয়ার আগেই তা শেষ করে দিতে পারে। সেক্ষেত্রে আপনাকে এগুলির পরিবর্তে অ্যালার্ম ব্যবহার করতে হবে।

এই পৃষ্ঠায় এই কাজগুলো বিস্তারিতভাবে বর্ণনা করা হয়েছে।

ম্যানিফেস্টের 'ব্যাকগ্রাউন্ড' ফিল্ডটি আপডেট করুন।

ম্যানিফেস্ট 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" ফিল্ডটি একটি একক স্ট্রিং গ্রহণ করে। আপনার কেবল তখনই "type" ফিল্ডটির প্রয়োজন হবে, যদি আপনি ES মডিউল ( import কীওয়ার্ড ব্যবহার করে) ব্যবহার করেন। এর মান সর্বদা "module" হবে। আরও তথ্যের জন্য, এক্সটেনশন সার্ভিস ওয়ার্কারের মৌলিক বিষয়াবলী দেখুন।

DOM এবং উইন্ডো কলগুলোকে একটি অফস্ক্রিন ডকুমেন্টে স্থানান্তর করুন

কিছু এক্সটেনশনের দৃশ্যত নতুন উইন্ডো বা ট্যাব না খুলেই DOM এবং উইন্ডো অবজেক্ট অ্যাক্সেস করার প্রয়োজন হয়। অফস্ক্রিন এপিআই ব্যবহারকারীর অভিজ্ঞতায় কোনো ব্যাঘাত না ঘটিয়ে, এক্সটেনশনের সাথে প্যাকেজ করা অপ্রদর্শিত ডকুমেন্টগুলো খোলা ও বন্ধ করার মাধ্যমে এই ধরনের ব্যবহারের ক্ষেত্রগুলোকে সমর্থন করে। মেসেজ পাসিং ছাড়া, অফস্ক্রিন ডকুমেন্টগুলো অন্যান্য এক্সটেনশন কনটেক্সটের সাথে এপিআই শেয়ার করে না, বরং এক্সটেনশনগুলোর ইন্টারঅ্যাক্ট করার জন্য পূর্ণাঙ্গ ওয়েব পেজ হিসেবে কাজ করে।

অফস্ক্রিন এপিআই ব্যবহার করতে, সার্ভিস ওয়ার্কার থেকে একটি অফস্ক্রিন ডকুমেন্ট তৈরি করুন।

chrome.offscreen.createDocument({
  url: chrome.runtime.getURL('offscreen.html'),
  reasons: ['CLIPBOARD'],
  justification: 'testing the offscreen API',
});

অফস্ক্রিন ডকুমেন্টে এমন যেকোনো কাজ সম্পাদন করুন যা আপনি আগে ব্যাকগ্রাউন্ড স্ক্রিপ্টে চালাতেন। উদাহরণস্বরূপ, আপনি হোস্ট পেজে নির্বাচিত টেক্সট কপি করতে পারেন।

let textEl = document.querySelector('#text');
textEl.value = data;
textEl.select();
document.execCommand('copy');

মেসেজ পাসিং ব্যবহার করে অফস্ক্রিন ডকুমেন্ট এবং সম্প্রসারণ পরিষেবা কর্মীদের মধ্যে যোগাযোগ স্থাপন করুন।

লোকালস্টোরেজকে অন্য প্রকারে রূপান্তর করুন

ওয়েব প্ল্যাটফর্মের Storage ইন্টারফেস (যা window.localStorage থেকে অ্যাক্সেসযোগ্য) একটি সার্ভিস ওয়ার্কারে ব্যবহার করা যায় না। এর সমাধান করতে দুটি কাজের মধ্যে একটি করুন। প্রথমত, আপনি এটিকে অন্য কোনো স্টোরেজ মেকানিজমের কল দিয়ে প্রতিস্থাপন করতে পারেন। chrome.storage.local নেমস্পেসটি বেশিরভাগ ক্ষেত্রে কাজ করবে, তবে অন্যান্য বিকল্পও রয়েছে।

আপনি এর কলগুলোকে একটি অফস্ক্রিন ডকুমেন্টে স্থানান্তর করতে পারেন। উদাহরণস্বরূপ, পূর্বে localStorage এ সংরক্ষিত ডেটা অন্য কোনো মেকানিজমে স্থানান্তর করতে:

  1. একটি রূপান্তর রুটিন এবং একটি runtime.onMessage হ্যান্ডলার সহ একটি অফস্ক্রিন ডকুমেন্ট তৈরি করুন।
  2. অফস্ক্রিন ডকুমেন্টে একটি রূপান্তর রুটিন যোগ করুন।
  3. এক্সটেনশন সার্ভিস ওয়ার্কারে আপনার ডেটার জন্য chrome.storage চেক করুন।
  4. যদি আপনার ডেটা খুঁজে না পাওয়া যায়, তাহলে একটি অফস্ক্রিন ডকুমেন্ট তৈরি করুন এবং রূপান্তর প্রক্রিয়াটি শুরু করতে runtime.sendMessage() কল করুন।
  5. অফস্ক্রিন ডকুমেন্টে আপনার যোগ করা runtime.onMessage হ্যান্ডলারে, কনভার্সন রুটিনটি কল করুন।

এক্সটেনশনগুলিতে ওয়েব স্টোরেজ এপিআই কীভাবে কাজ করে, তারও কিছু সূক্ষ্ম পার্থক্য রয়েছে। স্টোরেজ এবং কুকিজ- এ আরও জানুন।

শ্রোতাদের একযোগে নিবন্ধন করুন

ম্যানিফেস্ট V3-তে অ্যাসিঙ্ক্রোনাসভাবে (যেমন প্রমিজ বা কলব্যাকের ভিতরে) একটি লিসেনার রেজিস্টার করা হলে তা কাজ করবেই এমন কোনো নিশ্চয়তা নেই। নিম্নলিখিত কোডটি বিবেচনা করুন।

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.browserAction.setBadgeText({ text: badgeText });
  chrome.browserAction.onClicked.addListener(handleActionClick);
});

এটি একটি স্থায়ী ব্যাকগ্রাউন্ড পেজের সাথে কাজ করে, কারণ পেজটি ক্রমাগত চলতে থাকে এবং কখনও পুনরায় ইনিশিয়ালাইজ হয় না। ম্যানিফেস্ট V3-তে, ইভেন্টটি ডিসপ্যাচ করা হলে সার্ভিস ওয়ার্কারটি পুনরায় ইনিশিয়ালাইজ হবে। এর মানে হলো, যখন ইভেন্টটি ফায়ার হবে, তখন লিসেনারগুলো রেজিস্টার হবে না (যেহেতু সেগুলো অ্যাসিঙ্ক্রোনাসভাবে যুক্ত করা হয়), এবং ইভেন্টটি মিস হয়ে যাবে।

এর পরিবর্তে, ইভেন্ট লিসেনার রেজিস্ট্রেশনটি আপনার স্ক্রিপ্টের টপ লেভেলে নিয়ে যান। এটি নিশ্চিত করে যে, আপনার এক্সটেনশনটি তার স্টার্টআপ লজিক কার্যকর করা শেষ না করলেও, ক্রোম আপনার অ্যাকশনের ক্লিক হ্যান্ডলারকে অবিলম্বে খুঁজে পেতে এবং কল করতে সক্ষম হবে।

chrome.action.onClicked.addListener(handleActionClick);

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.action.setBadgeText({ text: badgeText });
});

XMLHttpRequest() কে global fetch() দিয়ে প্রতিস্থাপন করুন

সার্ভিস ওয়ার্কার, এক্সটেনশন বা অন্য কোনো উৎস থেকে XMLHttpRequest() কল করা যায় না। আপনার ব্যাকগ্রাউন্ড স্ক্রিপ্ট থেকে XMLHttpRequest() কল করার পরিবর্তে গ্লোবাল fetch() কল করুন।

XMLHttpRequest()
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);

স্থায়ী অবস্থা

সার্ভিস ওয়ার্কারগুলো ক্ষণস্থায়ী, যার মানে হলো একজন ব্যবহারকারীর ব্রাউজার সেশন চলাকালীন এগুলো সম্ভবত বারবার চালু, চালু এবং বন্ধ হবে। এর আরও একটি অর্থ হলো, যেহেতু পূর্ববর্তী কনটেক্সটটি ভেঙে ফেলা হয়, তাই গ্লোবাল ভেরিয়েবলগুলোতে ডেটা তাৎক্ষণিকভাবে পাওয়া যায় না। এই সমস্যা এড়ানোর জন্য, তথ্যের নির্ভরযোগ্য উৎস হিসেবে স্টোরেজ এপিআই ব্যবহার করুন। একটি উদাহরণে দেখানো হবে এটি কীভাবে করতে হয়।

নিম্নলিখিত উদাহরণটিতে একটি নাম সংরক্ষণ করার জন্য একটি গ্লোবাল ভেরিয়েবল ব্যবহার করা হয়েছে। একটি সার্ভিস ওয়ার্কারে, একজন ব্যবহারকারীর ব্রাউজার সেশন চলাকালীন এই ভেরিয়েবলটি একাধিকবার রিসেট করা হতে পারে।

ম্যানিফেস্ট ভি২ ব্যাকগ্রাউন্ড স্ক্রিপ্ট
let savedName = undefined;

chrome.runtime.onMessage.addListener(({ type, name }) => {
  if (type === "set-name") {
    savedName = name;
  }
});

chrome.browserAction.onClicked.addListener((tab) => {
  chrome.tabs.sendMessage(tab.id, { name: savedName });
});

Manifest V3-এর জন্য, গ্লোবাল ভেরিয়েবলটিকে Storage API- এর একটি কল দিয়ে প্রতিস্থাপন করুন।

ম্যানিফেস্ট ভি৩ পরিষেবা কর্মী
chrome.runtime.onMessage.addListener(({ type, name }) => {
  if (type === "set-name") {
    chrome.storage.local.set({ name });
  }
});

chrome.action.onClicked.addListener(async (tab) => {
  const { name } = await chrome.storage.local.get(["name"]);
  chrome.tabs.sendMessage(tab.id, { name });
});

টাইমারকে অ্যালার্মে রূপান্তর করুন

setTimeout() বা setInterval() মেথড ব্যবহার করে বিলম্বিত বা পর্যায়ক্রমিক অপারেশন করা একটি সাধারণ বিষয়। তবে, এই API-গুলো সার্ভিস ওয়ার্কারে ব্যর্থ হতে পারে, কারণ সার্ভিস ওয়ার্কারটি বন্ধ হয়ে গেলেই টাইমারগুলো বাতিল হয়ে যায়।

ম্যানিফেস্ট ভি২ ব্যাকগ্রাউন্ড স্ক্রিপ্ট
// 3 minutes in milliseconds
const TIMEOUT = 3 * 60 * 1000;
setTimeout(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
}, TIMEOUT);

এর পরিবর্তে, অ্যালার্ম এপিআই (Alarms API) ব্যবহার করুন। অন্যান্য লিসেনারের মতোই, অ্যালার্ম লিসেনারগুলোকেও আপনার স্ক্রিপ্টের টপ লেভেলে রেজিস্টার করতে হবে।

ম্যানিফেস্ট ভি৩ পরিষেবা কর্মী
async function startAlarm(name, duration) {
  await chrome.alarms.create(name, { delayInMinutes: 3 });
}

chrome.alarms.onAlarm.addListener(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
});

পরিষেবা কর্মীকে বাঁচিয়ে রাখুন

সার্ভিস ওয়ার্কার স্বভাবতই ইভেন্ট-চালিত এবং নিষ্ক্রিয়তায় বন্ধ হয়ে যায়। এর মাধ্যমে ক্রোম আপনার এক্সটেনশনের পারফরম্যান্স এবং মেমরি ব্যবহার অপ্টিমাইজ করতে পারে। আমাদের সার্ভিস ওয়ার্কার লাইফসাইকেল ডকুমেন্টেশনে এ বিষয়ে আরও জানুন। ব্যতিক্রমী ক্ষেত্রে, একটি সার্ভিস ওয়ার্কারকে দীর্ঘ সময় ধরে সচল রাখা নিশ্চিত করতে অতিরিক্ত পদক্ষেপের প্রয়োজন হতে পারে।

একটি দীর্ঘস্থায়ী অপারেশন শেষ না হওয়া পর্যন্ত একজন সার্ভিস কর্মীকে জীবিত রাখুন।

দীর্ঘক্ষণ ধরে চলা সার্ভিস ওয়ার্কার অপারেশন চলাকালীন, যেগুলো এক্সটেনশন এপিআই কল করে না, সার্ভিস ওয়ার্কারটি অপারেশনের মাঝপথে বন্ধ হয়ে যেতে পারে। উদাহরণস্বরূপ:

  • একটি fetch() অনুরোধে পাঁচ মিনিটের বেশি সময় লাগতে পারে (যেমন, দুর্বল সংযোগে কোনো বড় ফাইল ডাউনলোড করার ক্ষেত্রে)।
  • একটি জটিল অ্যাসিঙ্ক্রোনাস গণনা করতে ৩০ সেকেন্ডের বেশি সময় লাগছে।

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

নিম্নলিখিত উদাহরণটি একটি waitUntil() হেল্পার ফাংশন দেখায় যা একটি নির্দিষ্ট প্রমিস রিজলভ না হওয়া পর্যন্ত আপনার সার্ভিস ওয়ার্কারকে সচল রাখে:

async function waitUntil(promise) {
  const keepAlive = setInterval(chrome.runtime.getPlatformInfo, 25 * 1000);
  try {
    await promise;
  } finally {
    clearInterval(keepAlive);
  }
}

waitUntil(someExpensiveCalculation());

একজন পরিষেবা কর্মীকে ক্রমাগত বাঁচিয়ে রাখুন

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

আপনার সার্ভিস ওয়ার্কারকে সচল রাখতে নিম্নলিখিত কোড স্নিপেটটি ব্যবহার করুন:

/**
 * 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 chrome.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 chrome.storage.local.get('last-heartbeat'))['last-heartbeat'];
}