RocketChat/Rocket.Chat

View on GitHub
apps/meteor/public/workers/index.js

Summary

Maintainability
A
0 mins
Test Coverage
const HTMLToCache = '/';
const version = 'MSW V0.3';

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(version).then((cache) => {
            cache.add(HTMLToCache).then(self.skipWaiting());
        }),
    );
});

self.addEventListener('activate', (event) => {
    event.waitUntil(
        caches
            .keys()
            .then((cacheNames) =>
                Promise.all(
                    cacheNames.map((cacheName) => {
                        if (version !== cacheName) return caches.delete(cacheName);
                    }),
                ),
            )
            .then(self.clients.claim()),
    );
});

self.addEventListener('fetch', (event) => {
    const requestToFetch = event.request.clone();
    event.respondWith(
        caches.match(event.request.clone()).then((cached) => {
            // We don't return cached HTML (except if fetch failed)
            if (cached) {
                const resourceType = cached.headers.get('content-type');
                // We only return non css/js/html cached response e.g images
                if (!hasHash(event.request.url) && !/text\/html/.test(resourceType)) {
                    return cached;
                }

                // If the CSS/JS didn't change since it's been cached, return the cached version
                if (hasHash(event.request.url) && hasSameHash(event.request.url, cached.url)) {
                    return cached;
                }
            }
            return fetch(requestToFetch)
                .then((response) => {
                    const clonedResponse = response.clone();
                    const contentType = clonedResponse.headers.get('content-type');

                    if (
                        !clonedResponse ||
                        clonedResponse.status !== 200 ||
                        clonedResponse.type !== 'basic' ||
                        /\/sockjs\//.test(event.request.url)
                    ) {
                        return response;
                    }

                    if (/html/.test(contentType)) {
                        caches.open(version).then((cache) => cache.put(HTMLToCache, clonedResponse));
                    } else {
                        // Delete old version of a file
                        if (hasHash(event.request.url)) {
                            caches.open(version).then((cache) =>
                                cache.keys().then((keys) =>
                                    keys.forEach((asset) => {
                                        if (new RegExp(removeHash(event.request.url)).test(removeHash(asset.url))) {
                                            cache.delete(asset);
                                        }
                                    }),
                                ),
                            );
                        }

                        caches.open(version).then((cache) => cache.put(event.request, clonedResponse));
                    }
                    return response;
                })
                .catch(() => {
                    if (hasHash(event.request.url)) return caches.match(event.request.url);
                    // If the request URL hasn't been served from cache and isn't sockjs we suppose it's HTML
                    else if (!/\/sockjs\//.test(event.request.url)) return caches.match(HTMLToCache);
                    // Only for sockjs
                    return new Response('No connection to the server', {
                        status: 503,
                        statusText: 'No connection to the server',
                        headers: new Headers({ 'Content-Type': 'text/plain' }),
                    });
                });
        }),
    );
});

function removeHash(element) {
    if (typeof element === 'string') return element.split('?hash=')[0];
}

function hasHash(element) {
    if (typeof element === 'string') return /\?hash=.*/.test(element);
}

function hasSameHash(firstUrl, secondUrl) {
    if (typeof firstUrl === 'string' && typeof secondUrl === 'string') {
        return /\?hash=(.*)/.exec(firstUrl)[1] === /\?hash=(.*)/.exec(secondUrl)[1];
    }
}

// Service worker created by Ilan Schemoul alias NitroBAY as a specific Service Worker for Meteor
// Please see https://github.com/NitroBAY/meteor-service-worker for the official project source