`Service Worker` জাভাস্ক্রিপ্ট-এ

`Service Worker` জাভাস্ক্রিপ্ট-এ

এই নিবন্ধটি জাভাস্ক্রিপ্ট-এর Service Worker ধারণা ব্যাখ্যা করে।

আমরা ধাপে ধাপে Service Worker-এর মৌলিক বিষয় থেকে শুরু করে ব্যবহারিক ক্যাশ নিয়ন্ত্রণ পর্যন্ত ব্যাখ্যা করব।

YouTube Video

offline.html
 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4  <meta charset="UTF-8">
 5  <title>Offline</title>
 6</head>
 7<body>
 8  <h1>You are offline</h1>
 9  <p>This is the offline fallback page.</p>
10</body>
11</html>
style.css
1body {
2  font-family: sans-serif;
3  background-color: #f0f0f0;
4  padding: 20px;
5}
6h1 {
7  color: #333;
8}
javascript-service-worker.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>JavaScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    .container-flex {
 32        display: flex;
 33        flex-wrap: wrap;
 34        gap: 2em;
 35        max-width: 1000px;
 36        margin: 0 auto;
 37        padding: 1em;
 38        background-color: #ffffff;
 39        border: 1px solid #ccc;
 40        border-radius: 10px;
 41        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 42    }
 43
 44    .left-column, .right-column {
 45        flex: 1 1 200px;
 46        min-width: 200px;
 47    }
 48
 49    h1, h2 {
 50        font-size: 1.2rem;
 51        color: #007bff;
 52        margin-top: 0.5em;
 53        margin-bottom: 0.5em;
 54        border-left: 5px solid #007bff;
 55        padding-left: 0.6em;
 56        background-color: #e9f2ff;
 57    }
 58
 59    button {
 60        display: block;
 61        margin: 1em auto;
 62        padding: 0.75em 1.5em;
 63        font-size: 1rem;
 64        background-color: #007bff;
 65        color: white;
 66        border: none;
 67        border-radius: 6px;
 68        cursor: pointer;
 69        transition: background-color 0.3s ease;
 70    }
 71
 72    button:hover {
 73        background-color: #0056b3;
 74    }
 75
 76    #output {
 77        margin-top: 1em;
 78        background-color: #1e1e1e;
 79        color: #0f0;
 80        padding: 1em;
 81        border-radius: 8px;
 82        min-height: 200px;
 83        font-family: Consolas, monospace;
 84        font-size: 0.95rem;
 85        overflow-y: auto;
 86        white-space: pre-wrap;
 87    }
 88
 89    .highlight {
 90        outline: 3px solid #ffc107; /* yellow border */
 91        background-color: #fff8e1;  /* soft yellow background */
 92        transition: background-color 0.3s ease, outline 0.3s ease;
 93    }
 94
 95    .active {
 96        background-color: #28a745; /* green background */
 97        color: #fff;
 98        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 99        transition: background-color 0.3s ease, box-shadow 0.3s ease;
100    }
101  </style>
102</head>
103<body>
104    <div class="container">
105        <h1>JavaScript Console</h1>
106        <button id="executeBtn">Execute</button>
107        <div id="output"></div>
108    </div>
109
110    <div class="container">
111        <h2>HTML Sample</h2>
112        <button id="fetchBtn">Fetch Test</button>
113    </div>
114
115    <script>
116        // Override console.log to display messages in the #output element
117        (function () {
118            // Override console.log
119            const originalLog = console.log;
120            console.log = function (...args) {
121                originalLog.apply(console, args);
122                const message = document.createElement('div');
123                message.textContent = args.map(String).join(' ');
124                output.appendChild(message);
125            };
126
127            // Override console.error
128            const originalError = console.error;
129            console.error = function (...args) {
130                originalError.apply(console, args);
131                const message = document.createElement('div');
132                message.textContent = args.map(String).join(' ');
133                message.style.color = 'red'; // Color error messages red
134                output.appendChild(message);
135            };
136        })();
137
138        document.getElementById('executeBtn').addEventListener('click', () => {
139            // Prevent multiple loads
140            if (document.getElementById('externalScript')) return;
141
142            const script = document.createElement('script');
143            script.src = 'javascript-service-worker.js';
144            script.id = 'externalScript';
145            //script.onload = () => console.log('javascript-service-worker.js loaded and executed.');
146            //script.onerror = () => console.log('Failed to load javascript-service-worker.js.');
147            document.body.appendChild(script);
148        });
149    </script>
150</body>
151</html>

Service Worker জাভাস্ক্রিপ্ট-এ

Service Worker হলো জাভাস্ক্রিপ্ট-এর একটি ফিচার যা ব্রাউজার এবং নেটওয়ার্কের মাঝে অবস্থান নেয়, অনুরোধ ক্যাশিং এবং অফলাইন সাপোর্ট সক্ষম করে। এটি PWA (Progressive Web App)-এর অন্যতম প্রধান প্রযুক্তি এবং ওয়েব অ্যাপ্লিকেশনকে নেটিভ অ্যাপের মতো অভিজ্ঞতা প্রদান করে।

Service Worker কী?

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

Service Worker-এর মূল বৈশিষ্ট্যগুলো হলো:।

  • এটি শুধু HTTPS-এ কাজ করে, localhost ছাড়া।
  • এটি Promise-ভিত্তিক অ্যাসিনক্রোনাস API ব্যবহার করে।
  • এটি ইভেন্ট-চালিত, যেমন install, activate, fetch, এবং push ইভেন্ট ব্যবহার করে।

Service Worker রেজিস্ট্রেশন করা

প্রথমে, ব্রাউজারে Service Worker রেজিস্ট্রেশনের কোড লিখতে হবে।

 1if ('serviceWorker' in navigator) {
 2    window.addEventListener('load', () => {
 3        navigator.serviceWorker.register('/sw.js')
 4        .then(registration => {
 5            console.log(
 6                'Service Worker registered with scope:',
 7                registration.scope
 8            );
 9        })
10        .catch(error => {
11            console.error('Service Worker registration failed:', error);
12        });
13    });
14}

ব্যাখ্যা

  • navigator.serviceWorker.register() ব্যবহার করে /sw.js (অর্থাৎ Service Worker ফাইল) রেজিস্টার করুন।
  • রেজিস্ট্রেশনের সময় সফলতা পরিচালনার জন্য then এবং ত্রুটি পরিচালনার জন্য catch ব্যবহার করা যায়।
  • registration.scope দ্বারা বোঝানো হয় কোন পাথ সীমা (scope) এর উপর Service Worker প্রভাব ফেলে।
  • ডিফল্টভাবে, স্কোপটি সেই ডিরেক্টরি যেখানে রেজিস্টারকৃত ফাইল (এই ক্ষেত্রে, /sw.js) রয়েছে এবং তার সাবডিরেক্টরিগুলি।

Service Worker-এর স্কোপ

আপনি যদি স্কোপ সীমাবদ্ধ করতে চান, তাহলে register-এর দ্বিতীয় আর্গুমেন্ট ব্যবহার করে scope নির্দিষ্ট করতে পারেন।

1navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
2.then(registration => {
3    console.log(
4        'Service Worker registered with scope:',
5        registration.scope
6    );
7});

ব্যাখ্যা

  • এই সেটিংয়ের মাধ্যমে শুধুমাত্র /app/-এর অধীনে থাকা পেজগুলো Service Worker দ্বারা নিয়ন্ত্রিত হবে।

Service Worker ফাইল তৈরি করা

এরপর, sw.js নামে একটি ফাইল তৈরি করুন এবং মৌলিক ইভেন্টগুলো সংযোজন করুন।

1// sw.js
2const CACHE_NAME = 'my-cache-v1';
3const urlsToCache = [
4    '/',
5    '/index.html',
6    '/styles.css',
7    '/script.js',
8    '/offline.html'
9];

এই কোডটি ক্যাশে রাখার জন্য রিসোর্সের একটি তালিকা নির্ধারণ করে।

প্রতিটি ইভেন্টের ভূমিকা ও কার্যপ্রণালী

install

 1// Install event (initial caching)
 2self.addEventListener('install', event => {
 3    console.log('[ServiceWorker] Install');
 4    event.waitUntil(
 5        caches.open(CACHE_NAME).then(cache => {
 6            console.log('[ServiceWorker] Caching app shell');
 7            return cache.addAll(urlsToCache);
 8        })
 9    );
10});
  • self.addEventListener('install') তখনই চালু হয় যখন Service Worker প্রথমবার রেজিস্টার হয়। এই স্তরে, প্রয়োজনীয় ফাইলগুলো প্রি-ক্যাশ করা হয়।

activate

 1// Activation event (delete old caches)
 2self.addEventListener('activate', event => {
 3    console.log('[ServiceWorker] Activate');
 4    event.waitUntil(
 5        caches.keys().then(keyList => {
 6            return Promise.all(keyList.map(key => {
 7                if (key !== CACHE_NAME) {
 8                    console.log('[ServiceWorker] Removing old cache:', key);
 9                    return caches.delete(key);
10                }
11            }));
12        })
13    );
14    return self.clients.claim();
15});
  • activate ইভেন্টে, পুরনো ক্যাশগুলো মুছে ফেলে স্টোরেজ অপটিমাইজ করা হয়। শুধুমাত্র নতুন ভার্সনের ক্যাশ রাখা হয়।

fetch

1// Fetch event (cache-first strategy)
2self.addEventListener('fetch', event => {
3  console.log('[ServiceWorker] Fetch', event.request.url);
4    event.respondWith(
5        caches.match(event.request).then(response => {
6            return response || fetch(event.request).catch(() => caches.match('/offline.html'));
7        })
8    );
9});

সব HTTP অনুরোধ আটকানো হয়—যদি ক্যাশ করা সংস্করণ বিদ্যমান থাকে, তবে তা ফেরত দেওয়া হয়; না থাকলে নেটওয়ার্ক থেকে আনা হয়। অফলাইনে থাকলে বিকল্প কোনো পেজ (যেমন offline.html) ফিরিয়ে দেওয়া হয়।

অপারেশন নিশ্চিত করা হচ্ছে

আসুন আমরা আসলে দেখি কিভাবে Service Worker কাজ করে।

 1document.getElementById('fetchBtn').addEventListener('click', () => {
 2    fetch('/style.css')
 3        .then(response => response.text())
 4        .then(data => {
 5            console.log('Fetched data:', data);
 6        })
 7        .catch(error => {
 8            console.error('Fetch failed:', error);
 9        });
10});
  • এখানে, আমরা Service Worker-এর রেজিস্ট্রেশন এবং টেস্ট বোতাম ক্লিক করে রিসোর্স ফেচ করার কার্যকলাপ যাচাই করি।

ক্যাশিং কৌশলের উদাহরণ

নিম্নলিখিত হলো কিছু প্রচলিত ক্যাশিং কৌশল:।

ক্যাশ ফার্স্ট

ক্যাশ ফার্স্ট কৌশলের জন্য একটি উদাহরণ ইমপ্লিমেন্টেশনঃ।

1self.addEventListener('fetch', event => {
2    event.respondWith(
3        caches.match(event.request).then(response => {
4            return response || fetch(event.request);
5        })
6    );
7});
  • এই কোডটি একটি ক্যাশ-প্রথম কৌশল প্রয়োগ করে, যেখানে অনুরোধিত রিসোর্সটি ক্যাশে থাকলে তা ফেরত দেওয়া হয়; যদি না থাকে, তখন এটি নেটওয়ার্ক থেকে আনা হয়।

নেটওয়ার্ক ফার্স্ট

নেটওয়ার্ক ফার্স্ট কৌশলের জন্য একটি উদাহরণ ইমপ্লিমেন্টেশনঃ।

 1self.addEventListener('fetch', event => {
 2    event.respondWith(
 3        fetch(event.request)
 4            .then(response => {
 5                return caches.open(CACHE_NAME).then(cache => {
 6                    cache.put(event.request, response.clone());
 7                    return response;
 8                });
 9            })
10            .catch(() => caches.match(event.request))
11    );
12});
  • এই কোডটি একটি নেটওয়ার্ক-প্রথম কৌশল প্রয়োগ করে, যেখানে অনুরোধিত রিসোর্সটি প্রথমে নেটওয়ার্ক থেকে আনা হয়, এবং যদি তা ব্যর্থ হয়, তাহলে এটি ক্যাশ থেকে পুনরুদ্ধার করা হয়।

শুধুমাত্র স্টাইল ও জাভাস্ক্রিপ্ট ক্যাশ করুন, API-তে রিয়াল-টাইমে অ্যাক্সেস করুন

এখানে একটি উদাহরণ ইমপ্লিমেন্টেশন দেওয়া হলো যেখানে স্টাইল ও জাভাস্ক্রিপ্ট ক্যাশ হয়, আর API-তে রিয়াল-টাইমে অ্যাক্সেস করা হয়ঃ।

 1self.addEventListener('fetch', event => {
 2    if (event.request.url.includes('/api/')) {
 3        // Fetch API responses in real-time without caching
 4        return;
 5    }
 6
 7    // Use cache-first strategy for static files
 8    event.respondWith(
 9        caches.match(event.request).then(response => {
10            return response || fetch(event.request);
11        })
12    );
13});
  • এই কোডটি সবসময় এপিআই অনুরোধসমূহ তাৎক্ষণিকভাবে অ্যাক্সেস করে এবং স্ট্যাটিক ফাইল যেমন স্টাইলশিট ও জাভাস্ক্রিপ্টের জন্য ক্যাশ-প্রথম কৌশল প্রয়োগ করে।

আপডেট প্রবাহ

একটি সার্ভিস ওয়ার্কারের আপডেট প্রবাহ নিম্নরূপঃ।

১. নতুন sw.js শনাক্ত হয়। ২. install ইভেন্ট চালু হয়। ৩. পূর্ববর্তী Service Worker আইডল না হওয়া পর্যন্ত অপেক্ষা করা হয়। ৪. activate ইভেন্ট চালু হয়। ৫. নতুন Service Worker-এ পরিবর্তন হয়। ৬. controllerchange ইভেন্ট চালু হয়।

আপডেট সনাক্তকরণ

একবার Service Worker ইন্সটল হলে, পুরনোটি পরবর্তী ভিজিট পর্যন্ত ব্যবহার করা হয়। আপডেট কার্যকর করতে, সাধারণত এমন কোড ব্যবহার করা হয় যা আপডেট সনাক্ত করে এবং পৃষ্ঠা রিলোড করে।

1navigator.serviceWorker.addEventListener('controllerchange', () => {
2    window.location.reload();
3});
  • controllerchange ইভেন্টটি চালু হয় যখন সার্ভিস ওয়ার্কারের কন্ট্রোলার, অর্থাৎ বর্তমান পৃষ্ঠাটি নিয়ন্ত্রণকারী সার্ভিস ওয়ার্কারটি, পরিবর্তিত হয়।
  • যেসব পৃষ্ঠা ইতিমধ্যে খোলা আছে, সেগুলি বর্তমান সার্ভিস ওয়ার্কার ব্যবহার চালিয়ে যায়; নতুনভাবে ইনস্টল হওয়া সার্ভিস ওয়ার্কার সঙ্গে সঙ্গে ঐ পৃষ্ঠাগুলিতে কার্যকর হয় না। তাই, এমন একটি পদ্ধতি ব্যবহৃত হয় যেখানে controllerchange ইভেন্টটি ব্যবহার করে বোঝা যায় যে নতুন কন্ট্রোলার সক্রিয় হয়েছে; এরপর সাথে সাথে আপডেট কার্যকর করতে পৃষ্ঠাটি রিলোড করা হয়।

সতর্কতা ও সর্বোত্তম চর্চাসমূহ

Service Worker ব্যবহারের সময় নিম্নোক্ত বিষয়গুলো মনে রাখতে হবে:।

  • HTTPS প্রয়োজনীয় নিরাপত্তাজনিত কারণে, এটি localhost ছাড়া http://-এ কাজ করে না।

  • হ্যাশড ফাইল নাম ব্যবহার করুন ক্যাশ নামের মধ্যে ফাইল নাম, URL ও ভার্সন তথ্য থাকতে পারে।

  • ক্লায়েন্টের সাথে যোগাযোগ পৃষ্ঠার জাভাস্ক্রিপ্ট এবং Service Worker-এর মধ্যে যোগাযোগ করতে postMessage ব্যবহার করুন।

সারসংক্ষেপ

Service Worker ওয়েব অ্যাপগুলোর জন্য অফলাইন সমর্থন এবং পারফরমেন্স উন্নয়নের অপরিহার্য প্রযুক্তি। ইনস্টলেশন, অ্যাক্টিভেশন এবং ফেচ পরিচালনার মৌলিক প্রবাহ এবং উপযুক্ত ক্যাশিং কৌশল প্রয়োগের মাধ্যমে, আপনি আরও উন্নত মানের ওয়েব অ্যাপ তৈরি করতে পারবেন।

আপনি আমাদের ইউটিউব চ্যানেলে ভিজ্যুয়াল স্টুডিও কোড ব্যবহার করে উপরের নিবন্ধটি অনুসরণ করতে পারেন। দয়া করে ইউটিউব চ্যানেলটিও দেখুন।

YouTube Video