/**
* Import vendor modules
*/
const {Logger} = require('@neobeach/core');
/**
* Middleware to serve Manifest and Service Worker.
*
* @module @neobeach/middlewares-pwa
* @access public
* @since 1.0.0
* @author Glenn de Haan
* @copyright MIT
*
* @param {String} name - Completed full name of the application. (maximum of 45 characters)
* @param {String} shortName - Name to display when name is too long. (maximum of 12 characters recommended)
* @param {String} description - Description of the application
* @param {String} themeColor - Hex of the color that will be used as theme.
* @param {String} backgroundColor - Hex of the color that will be used as background color.
* @param {String} version - Version to give back in service worker.
* @param {Function|Boolean} [customServiceWorker] - Function to implement your own custom service worker.
* @return {function(*, *, *)}
*
* @example
* const {Runtime, Server} = require('@neobeach/core');
* const pwa = require('@neobeach/middlewares-pwa');
*
* const server = new Server();
*
* Runtime(() => {
* server.loadMiddlewares([pwa('Full Project', 'Project', "Description of Project",'#000000', '#000000', '1.0.0')]);
* server.run();
* });
*/
module.exports = (name, shortName, description, themeColor, backgroundColor, version, customServiceWorker = false) => {
Logger.info(`[PWA] Enabled! App Name: ${name}, App Short Name: ${shortName}, Theme Color: ${themeColor}, Background Color: ${backgroundColor}`);
Logger.info(`[PWA] Exposed: /manifest.json`);
Logger.info(`[PWA] Exposed: /sw.js`)
return (req, res, next) => {
/**
* Check if name is correct
*/
if(typeof name === "undefined" || typeof name !== "string" || name === "") {
Logger.error("[PWA] name is not correct");
process.exit(1);
return;
}
/**
* Check if shortName is correct
*/
if(typeof shortName === "undefined" || typeof shortName !== "string" || shortName === "") {
Logger.error("[PWA] shortName is not correct");
process.exit(1);
return;
}
/**
* Check if description is correct
*/
if(typeof description === "undefined" || typeof description !== "string" || description === "") {
Logger.error("[PWA] description is not correct")
process.exit(1);
return;
}
/**
* Check if themeColor is correct
*/
if(typeof themeColor === "undefined" || typeof themeColor !== "string" || themeColor === "") {
Logger.error("[PWA] themeColor is not correct");
process.exit(1);
return;
}
/**
* Check if backgroundColor is correct
*/
if(typeof backgroundColor === "undefined" || typeof backgroundColor !== "string" || backgroundColor === "") {
Logger.error("[PWA] backgroundColor is not correct");
process.exit(1);
return;
}
/**
* Check if version is correct
*/
if(typeof version === "undefined" || typeof version !== "string" || version === "") {
Logger.error("[PWA] version is not correct");
process.exit(1);
return;
}
if (req.originalUrl.indexOf("manifest.json") !== -1) {
const manifest = {
short_name: shortName,
name: name,
description: description,
icons: [
{
src: "/images/icons-192.png",
type: "image/png",
sizes: "192x192"
},
{
src: "/images/icons-512.png",
type: "image/png",
sizes: "512x512"
}
],
start_url: "/?source=pwa",
background_color: backgroundColor,
display: "standalone",
scope: "/",
theme_color: themeColor
};
res.json(manifest);
return;
}
if (req.originalUrl.indexOf("sw.js") !== -1) {
if(typeof customServiceWorker === "function") {
res.type("application/javascript");
res.send(customServiceWorker);
return;
}
const offlinePage = require('./page');
res.type("application/javascript");
res.send(`
const PRECACHE = 'precache-${version}';
const RUNTIME = 'runtime';
const PRECACHE_URLS = [];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(PRECACHE)
.then(cache => cache.addAll(PRECACHE_URLS))
.then(self.skipWaiting())
);
});
self.addEventListener('activate', event => {
const currentCaches = [PRECACHE];
event.waitUntil(
caches.keys().then(cacheNames => {
return cacheNames.filter(cacheName => !currentCaches.includes(cacheName));
}).then(cachesToDelete => {
return Promise.all(cachesToDelete.map(cacheToDelete => {
return caches.delete(cacheToDelete);
}));
}).then(() => self.clients.claim()));
});
self.addEventListener('fetch', event => {
if (event.request.url.startsWith(self.location.origin)) {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
if (cachedResponse) return cachedResponse;
return fetch(event.request).then(response => {
return response;
}).catch(() => new Response(\`${offlinePage}\`, {
headers: {'Content-Type': 'text/html'}
}));
}));
}
});`
);
return;
}
next();
}
}