From f24dd63551a3f8b9269e87e7390b1a8865b378e5 Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Wed, 22 Sep 2021 01:14:30 +0200 Subject: [PATCH] Workbox --- .env.development | 4 +- .eslintrc.js | 4 + package.json | 6 +- public/js/idb.js | 1 + public/js/workbox-sw-3-0-0.js.off | 3 - public/js/workbox-sw.js | 25 +- public/js/workbox-sw3-4-1.js.off | 3 - quasar.conf.js | 21 +- src-pwa/custom-service-worker.js | 163 +++++--- src-pwa/custom-service-worker.js.off | 564 +++++++++++++++++++++++++++ src/db/static_data.ts | 2 +- src/index.template.html | 2 - src/store/Api/index.ts | 2 +- src/store/UserStore.ts | 5 + src/store/globalStore.ts | 3 +- tsconfig.eslint.json | 7 + tsconfig.json | 9 +- 17 files changed, 707 insertions(+), 117 deletions(-) delete mode 100755 public/js/workbox-sw-3-0-0.js.off delete mode 100755 public/js/workbox-sw3-4-1.js.off create mode 100755 src-pwa/custom-service-worker.js.off create mode 100755 tsconfig.eslint.json diff --git a/.env.development b/.env.development index 1c6a8476..a35f0fe3 100755 --- a/.env.development +++ b/.env.development @@ -1,4 +1,4 @@ -APP_VERSION="0.1.1" +APP_VERSION="0.1.2" SERVICE_WORKER_FILE="service-worker.js" APP_ID="1" DIRECTORY_LOCAL="freeplanet" @@ -19,7 +19,7 @@ TEST_EMAIL="paolo@freeplanet.app" TEST_USERNAME="paoloar77" TEST_PASSWORD="passpao1fr@1A" TEST_APORTADOR="" -PUBLICKEY_PUSH='BGxRrFWnPoa_ImUaWXmeEOFVI9VNKVKaAPsvsM1XY6wn24yxp9MyOQ4crNYCJKxSXV65Y1GblW5_VLoamedcZ1I' +PUBLICKEY_PUSH='BDncvMiUZmjaCG2Kr1V9N0_33hOG-AuNSbHSvL24y2dzBiUjAxKm02emx5SeJvz2IGmtRf6YqCgopeQwCwUmZw8' IN_CONSTRUCTION="0" DEBUG="1" TELEGRAM_SUPPORT="" diff --git a/.eslintrc.js b/.eslintrc.js index c02fb927..1fb303bf 100755 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -19,6 +19,7 @@ module.exports = { ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features sourceType: 'module', // Allows for the use of imports }, + ignorePatterns: ["babel.config.js"], env: { node: true, @@ -162,4 +163,7 @@ module.exports = { }, ], }, + 'settings': { + 'import/resolver': 'webpack' + }, } diff --git a/package.json b/package.json index b84dc405..e3875f81 100755 --- a/package.json +++ b/package.json @@ -73,14 +73,14 @@ "@babel/eslint-parser": "^7.15.7", "@quasar/app": "^3.1.0", "@types/bcryptjs": "^2.4.2", - "@types/googlemaps": "^3.43.3", - "@types/vue-tel-input": "^2.1.2", - "@types/vuelidate": "^0.7.15", "@types/dotenv": "^8.2.0", + "@types/googlemaps": "^3.43.3", "@types/jest": "^27.0.1", "@types/js-cookie": "^2.2.7", "@types/node": "^16.9.2", "@types/nprogress": "^0.2.0", + "@types/vue-tel-input": "^2.1.2", + "@types/vuelidate": "^0.7.15", "@typescript-eslint/eslint-plugin": "^4.31.1", "@typescript-eslint/parser": "^4.31.1", "eslint": "^7.32.0", diff --git a/public/js/idb.js b/public/js/idb.js index 3feb6255..00f55a33 100755 --- a/public/js/idb.js +++ b/public/js/idb.js @@ -1,4 +1,5 @@ (function () { + console.log('LOADING IDB.JS .....') function toArray(arr) { return Array.prototype.slice.call(arr); } diff --git a/public/js/workbox-sw-3-0-0.js.off b/public/js/workbox-sw-3-0-0.js.off deleted file mode 100755 index 86617af1..00000000 --- a/public/js/workbox-sw-3-0-0.js.off +++ /dev/null @@ -1,3 +0,0 @@ -var workbox=function(){"use strict";try{self.workbox.v["workbox:sw:3.0.0"]=1}catch(t){}const t="https://storage.googleapis.com/workbox-cdn/releases/3.0.0",e={backgroundSync:"background-sync",core:"core",expiration:"cache-expiration",googleAnalytics:"google-analytics",strategies:"strategies",precaching:"precaching",routing:"routing",cacheableResponse:"cacheable-response",broadcastUpdate:"broadcast-cache-update",rangeRequests:"range-requests"};return new class{constructor(){return this.v={},this.t={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.e=this.t.debug?"dev":"prod",this.s=!1,new Proxy(this,{get(t,s){if(t[s])return t[s];const o=e[s];return o&&t.loadModule(`workbox-${o}`),t[s]}})}setConfig(t={}){if(this.s)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.t,t),this.e=this.t.debug?"dev":"prod"}skipWaiting(){self.addEventListener("install",()=>self.skipWaiting())}clientsClaim(){self.addEventListener("activate",()=>self.clients.claim())}loadModule(t){const e=this.o(t);try{importScripts(e),this.s=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}o(e){if(this.t.modulePathCb)return this.t.modulePathCb(e,this.t.debug);let s=[t];const o=`${e}.${this.e}.js`,r=this.t.modulePathPrefix;return r&&""===(s=r.split("/"))[s.length-1]&&s.splice(s.length-1,1),s.push(o),s.join("/")}}}(); - -//# sourceMappingURL=workbox-sw.js.map diff --git a/public/js/workbox-sw.js b/public/js/workbox-sw.js index 867e50b6..eceac39e 100755 --- a/public/js/workbox-sw.js +++ b/public/js/workbox-sw.js @@ -1,23 +1,2 @@ -const workbox = (function () { - try { self.workbox.v['workbox:sw:3.4.1'] = 1 } catch (t) {} const t = 'https://storage.googleapis.com/workbox-cdn/releases/3.4.1', - e = { - backgroundSync: 'background-sync', broadcastUpdate: 'broadcast-cache-update', cacheableResponse: 'cacheable-response', core: 'core', expiration: 'cache-expiration', googleAnalytics: 'google-analytics', navigationPreload: 'navigation-preload', precaching: 'precaching', rangeRequests: 'range-requests', routing: 'routing', strategies: 'strategies', streams: 'streams', - }; return new class { - constructor() { return this.v = {}, this.t = { debug: self.location.hostname === 'localhost', modulePathPrefix: null, modulePathCb: null }, this.e = this.t.debug ? 'dev' : 'prod', this.s = !1, new Proxy(this, { get(t, s) { if (t[s]) return t[s]; const o = e[s]; return o && t.loadModule(`workbox-${o}`), t[s] } }) } - - setConfig(t = {}) { if (this.s) throw new Error('Config must be set before accessing workbox.* modules'); Object.assign(this.t, t), this.e = this.t.debug ? 'dev' : 'prod' } - - skipWaiting() { self.addEventListener('install', () => self.skipWaiting()) } - - clientsClaim() { self.addEventListener('activate', () => self.clients.claim()) } - - loadModule(t) { const e = this.o(t); try { importScripts(e), this.s = !0 } catch (s) { throw console.error(`Unable to import module '${t}' from '${e}'.`), s } } - - o(e) { - if (this.t.modulePathCb) return this.t.modulePathCb(e, this.t.debug); let s = [t]; const o = `${e}.${this.e}.js`, - r = this.t.modulePathPrefix; return r && (s = r.split('/'))[s.length - 1] === '' && s.splice(s.length - 1, 1), s.push(o), s.join('/') - } - }() -}()); - -// # sourceMappingURL=workbox-sw.js.map +!function(){'use strict';try{self['workbox:sw:6.1.0']&&_()}catch(t){}const t={backgroundSync:'background-sync',broadcastUpdate:'broadcast-update',cacheableResponse:'cacheable-response',core:'core',expiration:'expiration',googleAnalytics:'offline-ga',navigationPreload:'navigation-preload',precaching:'precaching',rangeRequests:'range-requests',routing:'routing',strategies:'strategies',streams:'streams',recipes:'recipes'};self.workbox=new class{constructor(){return this.v={},this.Pt={debug:'localhost'===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.$t=this.Pt.debug?'dev':'prod',this.jt=!1,new Proxy(this,{get(e,s){if(e[s])return e[s];const o=t[s];return o&&e.loadModule('workbox-'+o),e[s]}})}setConfig(t={}){if(this.jt)throw new Error('Config must be set before accessing workbox.* modules');Object.assign(this.Pt,t),this.$t=this.Pt.debug?'dev':'prod'}loadModule(t){const e=this.St(t);try{importScripts(e),this.jt=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}St(t){if(this.Pt.modulePathCb)return this.Pt.modulePathCb(t,this.Pt.debug);let e=['https://storage.googleapis.com/workbox-cdn/releases/6.1.0'];const s=`${t}.${this.$t}.js`,o=this.Pt.modulePathPrefix;return o&&(e=o.split('/'),''===e[e.length-1]&&e.splice(e.length-1,1)),e.push(s),e.join('/')}}}(); +//# sourceMappingURL=workbox-sw.js.map diff --git a/public/js/workbox-sw3-4-1.js.off b/public/js/workbox-sw3-4-1.js.off deleted file mode 100755 index 0908b00d..00000000 --- a/public/js/workbox-sw3-4-1.js.off +++ /dev/null @@ -1,3 +0,0 @@ -var workbox=function(){"use strict";try{self.workbox.v["workbox:sw:3.4.1"]=1}catch(t){}const t="https://storage.googleapis.com/workbox-cdn/releases/3.4.1",e={backgroundSync:"background-sync",broadcastUpdate:"broadcast-cache-update",cacheableResponse:"cacheable-response",core:"core",expiration:"cache-expiration",googleAnalytics:"google-analytics",navigationPreload:"navigation-preload",precaching:"precaching",rangeRequests:"range-requests",routing:"routing",strategies:"strategies",streams:"streams"};return new class{constructor(){return this.v={},this.t={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.e=this.t.debug?"dev":"prod",this.s=!1,new Proxy(this,{get(t,s){if(t[s])return t[s];const o=e[s];return o&&t.loadModule(`workbox-${o}`),t[s]}})}setConfig(t={}){if(this.s)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.t,t),this.e=this.t.debug?"dev":"prod"}skipWaiting(){self.addEventListener("install",()=>self.skipWaiting())}clientsClaim(){self.addEventListener("activate",()=>self.clients.claim())}loadModule(t){const e=this.o(t);try{importScripts(e),this.s=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}o(e){if(this.t.modulePathCb)return this.t.modulePathCb(e,this.t.debug);let s=[t];const o=`${e}.${this.e}.js`,r=this.t.modulePathPrefix;return r&&""===(s=r.split("/"))[s.length-1]&&s.splice(s.length-1,1),s.push(o),s.join("/")}}}(); - -//# sourceMappingURL=workbox-sw.js.map diff --git a/quasar.conf.js b/quasar.conf.js index a91e05ca..a5a27c95 100755 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -17,6 +17,8 @@ const webpack = require('webpack') const helpers = require('./helpers') const envparser = require('./config/envparser') +const ESLintPlugin = require('eslint-webpack-plugin') + module.exports = configure((ctx) => ({ // https://v2.quasar.dev/quasar-cli/supporting-ts supportTS: { @@ -288,27 +290,12 @@ module.exports = configure((ctx) => ({ theme_color: '#027be3', icons: [ { - src: 'icons/icon-128x128.png', - sizes: '128x128', - type: 'image/png', - }, - { - src: 'icons/icon-192x192.png', - sizes: '192x192', - type: 'image/png', - }, - { - src: 'icons/icon-256x256.png', - sizes: '256x256', - type: 'image/png', - }, - { - src: 'icons/icon-384x384.png', + src: 'icons/android-chrome-192x192.png', sizes: '384x384', type: 'image/png', }, { - src: 'icons/icon-512x512.png', + src: 'icons/android-chrome-512x512.png', sizes: '512x512', type: 'image/png', }, diff --git a/src-pwa/custom-service-worker.js b/src-pwa/custom-service-worker.js index 6521ebda..9b4dfee9 100755 --- a/src-pwa/custom-service-worker.js +++ b/src-pwa/custom-service-worker.js @@ -1,24 +1,39 @@ -/* - * This file (which will be your service worker) - * is picked up by the build system ONLY if - * quasar.conf > pwa > workboxPluginMode is set to "InjectManifest" - */ +import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching' +import { registerRoute } from 'workbox-routing' -// Questo รจ il swSrc +import { clientsClaim, setCacheNameDetails, skipWaiting } from 'workbox-core' -console.log(' [ VER-0.0.63 ] _---------________------ PAO: this is my custom service worker') +import { + NetworkFirst, + NetworkOnly, + StaleWhileRevalidate, + CacheFirst, +} from 'workbox-strategies' -importScripts('../public/js/idb.js') -importScripts('../public/js/storage.js') -importScripts('../public/js/workbox-sw.js') +// Used for filtering matches based on status code, header, or both +import { CacheableResponsePlugin } from 'workbox-cacheable-response' +// Used to limit entries in cache, remove entries after a certain period of time +import { ExpirationPlugin } from 'workbox-expiration' + +console.log( + ' [ VER-0.0.65 ] _---------________------ PAO: this is my custom service worker') + +importScripts('js/idb.js') +importScripts('js/storage.js') +importScripts('js/workbox-sw.js') + +// importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.2.0/workbox-sw.js'); // importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); +// importScripts('./ChabokSDKWorker.js', 'https://storage.googleapis.com/workbox-cdn/releases/5.0.0/workbox-sw.js'); + let port = 3000 if (self.location.hostname.startsWith('test')) { port = 3001 } -// console.log('SW-06 1'); +console.log('SW-06 1') + const cfgenv = { serverweb: `${self.location.protocol}//${self.location.hostname}:${port}`, dbname: 'mydb3', @@ -27,22 +42,22 @@ const cfgenv = { // console.log('serverweb', cfgenv.serverweb) -async function writeData(table, data) { +async function writeData (table, data) { // console.log('writeData', table, data); await idbKeyval.setdata(table, data) } -async function readAllData(table) { +async function readAllData (table) { // console.log('readAllData', table); return idbKeyval.getalldata(table) } -async function clearAllData(table) { +async function clearAllData (table) { // console.log('clearAllData', table); await idbKeyval.clearalldata(table) } -async function deleteItemFromData(table, id) { +async function deleteItemFromData (table, id) { // console.log('deleteItemFromData', table, 'ID:', id); await idbKeyval.deletedata(table, id) @@ -59,31 +74,33 @@ if (!workbox) { } if (workbox) { - // console.log('WORKBOX PRESENT') - // const url = new URL(location.href); - // const debug = url.searchParams.has('debug'); - const debug = false + const debug = true workbox.setConfig({ debug }) - workbox.core.setCacheNameDetails({ prefix: self.location.hostname }) + const precacheList = self.__WB_MANIFEST || []; + setCacheNameDetails({ + prefix: self.location.hostname, + suffix: 'v1', + precache: 'precache', + runtime: 'runtime' + }) - /** - * The workboxSW.precacheAndRoute() method efficiently caches and responds to - * requests for URLs in the manifest. - * See https://goo.gl/S9QRab - */ - self.__precacheManifest = [].concat(self.__precacheManifest || []) - workbox.precaching.suppressWarnings() - workbox.precaching.precacheAndRoute(self.__precacheManifest, {}) + // clientsClaim() + // skipWaiting() - // workbox.routing.registerRoute(/^http/, workbox.strategies.networkFirst(), 'GET'); + precacheAndRoute(precacheList) + // cleanupOutdatedCaches() - workbox.routing.registerRoute( + registerRoute( new RegExp(/\.(?:png|gif|jpg|jpeg|svg)$/), - new workbox.strategies.CacheFirst({ + new CacheFirst({ cacheName: 'images', plugins: [ - new workbox.expiration.Plugin({ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ maxEntries: 60, maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days }), @@ -92,25 +109,33 @@ if (workbox) { ) // Per Articoli.... - const articleHandler = workbox.strategies.networkFirst({ + const articleHandler = new NetworkFirst({ cacheName: 'articles-cache', plugins: [ - new workbox.expiration.Plugin({ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ maxEntries: 50, }), ], }) - workbox.routing.registerRoute( + registerRoute( new RegExp(/(.*)article(.*)\.html/), args => articleHandler.handle(args), ) - workbox.routing.registerRoute( + registerRoute( new RegExp(/.*(?:googleapis|gstatic)\.com.*$/), - workbox.strategies.staleWhileRevalidate({ + new StaleWhileRevalidate({ cacheName: 'google-fonts', plugins: [ - new workbox.expiration.Plugin({ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ maxEntries: 30, }), ], @@ -119,7 +144,7 @@ if (workbox) { // console.log(' routing.registerRoute function declaration:') - function Execute_Fetch(table, args) { + function Execute_Fetch (table, args) { console.log('Execute_Fetch registerRoute! ', `${cfgenv.serverweb}/${table}/`) // console.log('DATABODY:', args.event.request.body) @@ -157,7 +182,7 @@ if (workbox) { .then(data => { // console.log(' 4) data = ', data) if (data) { - myarr = idbKeyval.getArrayByTable(table, data) + const myarr = idbKeyval.getArrayByTable(table, data) if (myarr) { let promiseChain = Promise.resolve() @@ -198,7 +223,7 @@ if (workbox) { } for (const table of MainTables) { - workbox.routing.registerRoute( + registerRoute( new RegExp(`${cfgenv.serverweb}/${table}/`), (args) => { Execute_Fetch(table, args) @@ -206,7 +231,7 @@ if (workbox) { ) } - workbox.routing.registerRoute( + registerRoute( (routeData) => (routeData.event.request.headers.get('accept') .includes('text/html')), (args) => caches.match(args.event.request) .then((response) => { @@ -224,32 +249,46 @@ if (workbox) { }), ) - workbox.routing.registerRoute( + registerRoute( new RegExp(/.*\/(?:statics\/icons).*$/), - new workbox.strategies.CacheFirst({ + new CacheFirst({ cacheName: 'image-cache', plugins: [ - new workbox.expiration.Plugin({ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ maxAgeSeconds: 30 * 24 * 60 * 60, }), ], }), ) - workbox.routing.registerRoute( + registerRoute( new RegExp(/\.(?:js|css|font)$/), - new workbox.strategies.StaleWhileRevalidate({ + new StaleWhileRevalidate({ cacheName: 'js-css-fonts', + // Ensure that only requests that result in a 200 status are cached + plugins: [ + new CacheableResponsePlugin({ + statuses: [200], + }), + ], }), ) // Storage - workbox.routing.registerRoute( + registerRoute( new RegExp(/.*(?:storage)/), - workbox.strategies.staleWhileRevalidate({ + new StaleWhileRevalidate({ cacheName: 'storage', plugins: [ - new workbox.expiration.Plugin({ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ maxAgeSeconds: 30 * 24 * 60 * 60, // Only cache 10 requests. maxEntries: 200, @@ -258,12 +297,16 @@ if (workbox) { }), ) - workbox.routing.registerRoute( + registerRoute( new RegExp(/.*\/(?:statics).*$/), - new workbox.strategies.CacheFirst({ + new CacheFirst({ cacheName: 'statics', plugins: [ - new workbox.expiration.Plugin({ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ maxAgeSeconds: 10 * 24 * 60 * 60, // Only cache 10 requests. }), @@ -271,15 +314,17 @@ if (workbox) { }), ) - workbox.routing.registerRoute( + registerRoute( new RegExp('/admin/'), - workbox.strategies.networkOnly(), + new NetworkOnly(), ) - workbox.routing.registerRoute( + /*registerRoute( new RegExp('/owa/'), - workbox.strategies.networkOnly(), + new NetworkOnly(), ) + */ + } if ('serviceWorker' in navigator) { @@ -290,8 +335,8 @@ if ('serviceWorker' in navigator) { // self.addEventListener('fetch', (event) => { // if (event.request.url === '/') { -// const staleWhileRevalidate = new workbox.strategies.StaleWhileRevalidate(); -// event.respondWith(staleWhileRevalidate.handle({ event })); +// const StaleWhileRevalidate = new StaleWhileRevalidate(); +// event.respondWith(StaleWhileRevalidate.handle({ event })); // } // }); diff --git a/src-pwa/custom-service-worker.js.off b/src-pwa/custom-service-worker.js.off new file mode 100755 index 00000000..6d43363f --- /dev/null +++ b/src-pwa/custom-service-worker.js.off @@ -0,0 +1,564 @@ + +import { precacheAndRoute } from 'workbox-precaching' +import { registerRoute } from 'workbox-routing' +import { + NetworkFirst, + NetworkOnly, + StaleWhileRevalidate, + CacheFirst, +} from 'workbox-strategies' + +// Used for filtering matches based on status code, header, or both +import { CacheableResponsePlugin } from 'workbox-cacheable-response' +// Used to limit entries in cache, remove entries after a certain period of time +import { ExpirationPlugin } from 'workbox-expiration' + +// Use with precache injection +precacheAndRoute(self.__WB_MANIFEST) + +console.log( + ' [ VER-0.0.63 ] _---------________------ PAO: this is my custom service worker') + +importScripts('js/idb.js') +importScripts('js/storage.js') +importScripts('js/workbox-sw.js') + +// importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); + +// importScripts('./ChabokSDKWorker.js', 'https://storage.googleapis.com/workbox-cdn/releases/5.0.0/workbox-sw.js'); + +let port = 3000 +if (self.location.hostname.startsWith('test')) { + port = 3001 +} +console.log('SW-06 1') + +const cfgenv = { + serverweb: `${self.location.protocol}//${self.location.hostname}:${port}`, + dbname: 'mydb3', + dbversion: 11, +} + +// console.log('serverweb', cfgenv.serverweb) + +async function writeData (table, data) { + // console.log('writeData', table, data); + await idbKeyval.setdata(table, data) +} + +async function readAllData (table) { + // console.log('readAllData', table); + return idbKeyval.getalldata(table) +} + +async function clearAllData (table) { + // console.log('clearAllData', table); + await idbKeyval.clearalldata(table) +} + +async function deleteItemFromData (table, id) { + // console.log('deleteItemFromData', table, 'ID:', id); + + await idbKeyval.deletedata(table, id) +} + +// self.addEventListener('activate', function(event) { +// event.waitUntil( +// // createDB() +// ); +// }); + +if (!workbox) { + const workbox = new self.WorkboxSW() +} + +if (workbox) { + // console.log('WORKBOX PRESENT') + // const url = new URL(location.href); + // const debug = url.searchParams.has('debug'); + const debug = false + workbox.setConfig({ debug }) + + // workbox.setCacheNameDetails({ prefix: self.location.hostname }) + + registerRoute( + new RegExp(/\.(?:png|gif|jpg|jpeg|svg)$/), + new CacheFirst({ + cacheName: 'images', + plugins: [ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ + maxEntries: 60, + maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days + }), + ], + }), + ) + + // Per Articoli.... + const articleHandler = new NetworkFirst({ + cacheName: 'articles-cache', + plugins: [ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ + maxEntries: 50, + }), + ], + }) + + registerRoute( + new RegExp(/(.*)article(.*)\.html/), args => articleHandler.handle(args), + ) + + registerRoute( + new RegExp(/.*(?:googleapis|gstatic)\.com.*$/), + new StaleWhileRevalidate({ + cacheName: 'google-fonts', + plugins: [ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ + maxEntries: 30, + }), + ], + }), + ) + + // console.log(' routing.registerRoute function declaration:') + + function Execute_Fetch (table, args) { + console.log('Execute_Fetch registerRoute! ', + `${cfgenv.serverweb}/${table}/`) + // console.log('DATABODY:', args.event.request.body) + let myres = null + // return fetch(args.event.request, args.event.headers) + return fetch(args.event.request, args.event.headers) + .then((res) => { + myres = res + if (res.status === 200) { + const clonedRes = res.clone() + + let secondatab = '' + if (table === 'todos') { + secondatab = 'categories' + } + console.log('1) clearAllData: ', table) + return clearAllData(table) + .then(() => { + if (secondatab !== '') { + // console.log('2) clearAllData(todos)') + return clearAllData(secondatab) + .then(() => + // console.log('3) ....return clonedRes') + clonedRes) + } + return clonedRes + }) + } + }) + .then((clonedRes) => { + // console.log(' 3) ') + if (clonedRes) return clonedRes.json() + return null + }) + .then(data => { + // console.log(' 4) data = ', data) + if (data) { + const myarr = idbKeyval.getArrayByTable(table, data) + if (myarr) { + let promiseChain = Promise.resolve() + + console.log('*********+++++++++++++++++********** Records ', + `${table} Received from Server [`, myarr.length, 'record]', myarr) + + if (table === 'todos') { + for (const cat in data.categories) { + promiseChain = promiseChain.then(() => writeData('categories', { + _id: cat, + valore: data.categories[cat], + })) + } + + for (const arrsing of myarr) { + for (const rec of arrsing) { + promiseChain = promiseChain.then(() => writeData(table, rec)) + } + } + } else { + // Others tables + for (const rec of myarr) { + promiseChain = promiseChain.then(() => writeData(table, rec)) + } + } + + // console.log('promiseChain', promiseChain) + + return promiseChain + } + } + }) + .then(() => myres) + .catch(err => { + console.log('ERROR registerRoute FETCH:', err) + return myres + }) + } + + for (const table of MainTables) { + registerRoute( + new RegExp(`${cfgenv.serverweb}/${table}/`), + (args) => { + Execute_Fetch(table, args) + }, + ) + } + + registerRoute( + (routeData) => (routeData.event.request.headers.get('accept') + .includes('text/html')), (args) => caches.match(args.event.request) + .then((response) => { + if (response) { + return response + } + return fetch(args.event.request) + .then((res) => caches.open('dynamic') + .then((cache) => { + cache.put(args.event.request.url, res.clone()) + return res + })) + .catch((err) => caches.match('/offline') + .then((res) => res)) + }), + ) + + registerRoute( + new RegExp(/.*\/(?:statics\/icons).*$/), + new CacheFirst({ + cacheName: 'image-cache', + plugins: [ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ + maxAgeSeconds: 30 * 24 * 60 * 60, + }), + ], + }), + ) + + registerRoute( + new RegExp(/\.(?:js|css|font)$/), + new StaleWhileRevalidate({ + cacheName: 'js-css-fonts', + // Ensure that only requests that result in a 200 status are cached + plugins: [ + new CacheableResponsePlugin({ + statuses: [200], + }), + ], + }), + ) + + // Storage + registerRoute( + new RegExp(/.*(?:storage)/), + new StaleWhileRevalidate({ + cacheName: 'storage', + plugins: [ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ + maxAgeSeconds: 30 * 24 * 60 * 60, + // Only cache 10 requests. + maxEntries: 200, + }), + ], + }), + ) + + registerRoute( + new RegExp(/.*\/(?:statics).*$/), + new CacheFirst({ + cacheName: 'statics', + plugins: [ + // Ensure that only requests that result in a 200 status are cached + new CacheableResponsePlugin({ + statuses: [200], + }), + new ExpirationPlugin({ + maxAgeSeconds: 10 * 24 * 60 * 60, + // Only cache 10 requests. + }), + ], + }), + ) + + registerRoute( + new RegExp('/admin/'), + new NetworkOnly(), + ) + + registerRoute( + new RegExp('/owa/'), + new NetworkOnly(), + ) +} + +if ('serviceWorker' in navigator) { + + // console.log('***************** Entering in custom-service-worker.js:') + +} + +// self.addEventListener('fetch', (event) => { +// if (event.request.url === '/') { +// const StaleWhileRevalidate = new StaleWhileRevalidate(); +// event.respondWith(StaleWhileRevalidate.handle({ event })); +// } +// }); + +// self.addEventListener('fetch', function (event) { +// console.log('[Service Worker] Fetching something ....', event); +// console.log('event.request.cache=', event.request.cache) +// if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { +// console.log('SAME ORIGIN!', event); +// return; +// } +// event.respondWith(caches.match(event.request)); +// }); +// + +// const syncStore = {} +// self.addEventListener('message', event => { +// if (event.data.type === 'sync') { +// // get a unique id to save the data +// const id = uuid() +// syncStore[id] = event.data +// // register a sync and pass the id as tag for it to get the data +// self.registration.sync.register(id) +// } +// console.log(event.data) +// }) + +// addEventListener('fetch', event => { +// // Prevent the default, and handle the request ourselves. +// event.respondWith(async function() { +// // Try to get the response from a cache. +// const cachedResponse = await caches.match(event.request); +// // Return it if we found one. +// if (cachedResponse && (event.request.cache !== 'no-cache')) +// return cachedResponse; +// +// // If we didn't find a match in the cache, use the network. +// return fetch(event.request); +// }()); +// }); + +// self.addEventListener('fetch', function (event) { +// event.respondWith( +// caches.match(event.request).then(function (response) { +// return response || +// fetch(event.request, event.headers) +// .catch(err => { +// console.log('_______________________ ERRORE FETCH SW: ', event.request, err) +// writeData('config', { _id: 2, stateconn: 'offline' }) +// return caches.match(event.request); +// }) +// }) +// ); +// }); + +// self.addEventListener('fetch', function (event) { +// event.respondWith( +// fetch(event.request, event.headers) +// .catch(err => { +// console.log('_______________________ ERRORE FETCH SW: ', event.request, err) +// writeData('config', {_id: 2, stateconn: 'offline'}) +// return caches.match(event.request); +// }) +// ); +// }); + +// self.addEventListener('sync', function (event) { +// console.log('[Service Worker V5] Background syncing', event.tag); +// +// let mystrparam = event.tag +// let multiparams = mystrparam.split('|') +// if (multiparams) { +// if (multiparams.length > 3) { +// let cmd = multiparams[0] +// let table = multiparams[1] +// let method = multiparams[2] +// let token = multiparams[3] +// // let lang = multiparams[3] +// +// if (cmd === 'sync-todos') { +// console.log('[Service Worker] Syncing', cmd, table, method); +// +// const headers = new Headers() +// headers.append('content-Type', 'application/json') +// headers.append('Accept', 'application/json') +// headers.append('x-auth', token) +// +// +// // console.log('A1) INIZIO.............................................................'); +// +// event.waitUntil( +// readAllData(table) +// .then(function (alldata) { +// const myrecs = [...alldata] +// console.log('----------------------- LEGGO QUALCOSA DAL WAITUNTIL ') +// let errorfromserver = false +// if (myrecs) { +// for (let rec of myrecs) { +// //console.log('syncing', table, '', rec.descr) +// let link = cfgenv.serverweb + '/todos' +// +// if (method !== 'POST') +// link += '/' + rec._id +// +// console.log('++++++++++++++++++ SYNCING !!!! ', rec.descr, table, 'FETCH: ', method, link, 'data:') +// +// // console.log('DATATOSAVE:', JSON.stringify(rec)) +// +// // Insert/Delete/Update table to the server +// fetch(link, { +// method: method, +// headers: headers, +// cache: 'no-cache', +// mode: 'cors', // 'no-cors', +// body: JSON.stringify(rec) +// }) +// .then(() => { +// deleteItemFromData(table, rec._id) +// }) +// .then(() => { +// deleteItemFromData('swmsg', mystrparam) +// }) +// .catch(function (err) { +// console.log('!!!!!!!!!!!!!!! Error while sending data', err, err.message); +// if (err.message === 'Failed to fetch') { +// errorfromserver = true +// } +// }) +// } +// return errorfromserver +// } +// }) +// .then((errorfromserver) => { +// const mystate = !errorfromserver ? 'online' : 'offline' +// writeData('config', { _id: 2, stateconn: mystate }) +// }) +// ); +// // console.log('A2) ?????????????????????????? ESCO DAL LOOP !!!!!!!!! err=') +// } +// } +// } +// }) +// ; + +/* + +// send message to serviceWorker +function sync (url, options) { + navigator.serviceWorker.controller.postMessage({type: 'sync', url, options}) +} + +const syncStore = {} +self.addEventListener('message', event => { + if(event.data.type === 'sync') { + // get a unique id to save the data + const id = uuid() + syncStore[id] = event.data + // register a sync and pass the id as tag for it to get the data + self.registration.sync.register(id) + } + console.log(event.data) +}) + +self.addEventListener('sync', event => { + // get the data by tag + const {url, options} = syncStore[event.tag] + event.waitUntil(fetch(url, options)) +}) +*/ + +self.addEventListener('notificationclick', (event) => { + const { notification } = event + const { action } = event + + console.log(notification) + + if (action === 'confirm') { + console.log('Confirm was chosen') + notification.close() + } else { + console.log(action) + event.waitUntil( + clients.matchAll() + .then((clis) => { + const client = clis.find((c) => c.visibilityState === 'visible') + + if (client) { + client.navigate(notification.data.url) + client.focus() + } else { + clients.openWindow(notification.data.url) + } + notification.close() + }), + ) + } +}) + +self.addEventListener('notificationclose', (event) => { + console.log('Notification was closed', event) +}) + +self.addEventListener('push', (event) => { + console.log('Push Notification received', event) + + let data = { + title: 'New!', + content: 'Something new happened!', + url: '/', + } + + try { + if (event.data) { + try { + data = JSON.parse(event.data.text()) + } catch (e) { + data = event.data.text() + } + } + + const options = { + body: data.content, + icon: '/public/icons/android-chrome-192x192.png', + badge: '/public/icons/android-chrome-192x192.png', + data: { + url: data.url, + }, + tag: 'received', + renitify: true, // vibrate also with others messages. + } + + event.waitUntil( + self.registration.showNotification(data.title, options), + ) + } catch (e) { + console.log('Error on event push:', e) + } +}) diff --git a/src/db/static_data.ts b/src/db/static_data.ts index 7efede40..d1a89c8a 100755 --- a/src/db/static_data.ts +++ b/src/db/static_data.ts @@ -6,7 +6,7 @@ import { } from '@model' const functionality: IFunctionality = { - PWA: false, + PWA: true, SHOW_USER_MENU: true, // Cambiare con true SHOW_PROFILE: true, SHOW_REG_BUTTON: true, diff --git a/src/index.template.html b/src/index.template.html index 8157cbff..d430e5e1 100755 --- a/src/index.template.html +++ b/src/index.template.html @@ -9,8 +9,6 @@ - - diff --git a/src/store/Api/index.ts b/src/store/Api/index.ts index 5b24e549..fa377f8b 100755 --- a/src/store/Api/index.ts +++ b/src/store/Api/index.ts @@ -103,7 +103,7 @@ export const Api = { // eslint-disable-next-line @typescript-eslint/no-misused-promises return new Promise((resolve, reject) => sendRequest(url, method, mydataout) .then((res) => { - // console.log('res', res) + console.log('status:', res.status) setTimeout(() => { if (method === 'get') { diff --git a/src/store/UserStore.ts b/src/store/UserStore.ts index 88869723..37bdb7d7 100755 --- a/src/store/UserStore.ts +++ b/src/store/UserStore.ts @@ -561,6 +561,7 @@ export const useUserStore = defineStore('UserStore', { try { if (static_data.functionality.PWA) { if ('serviceWorker' in navigator) { + console.log('serviceWorker') sub = await navigator.serviceWorker.ready .then((swreg) => { console.log('swreg') @@ -586,6 +587,8 @@ export const useUserStore = defineStore('UserStore', { openUrl: '/', } + console.log('2') + const usertosend = { username: authData.username.trim(), password: authData.password.trim(), @@ -604,6 +607,7 @@ export const useUserStore = defineStore('UserStore', { return Api.SendReq('/users/login', 'POST', usertosend, true) .then((res) => { + myres = res if (myres.status !== 200) { @@ -643,6 +647,7 @@ export const useUserStore = defineStore('UserStore', { } }) .catch((error) => { + console.log('error', error) this.setErrorCatch(error) return this.getServerCode }) diff --git a/src/store/globalStore.ts b/src/store/globalStore.ts index 12e4899d..5474585d 100644 --- a/src/store/globalStore.ts +++ b/src/store/globalStore.ts @@ -463,7 +463,7 @@ export const useGlobalStore = defineStore('GlobalStore', { return swreg.pushManager.getSubscription() }) .then((subscription) => { - console.log('subscription = ', subscription) + console.log('!!!!!!!! subscription = ', subscription) this.wasAlreadySubscribed = !(subscription === null) @@ -491,6 +491,7 @@ export const useGlobalStore = defineStore('GlobalStore', { // Calling the Server to Save in the MongoDB the Subscriber saveNewSubscriptionToServer(newSub: any) { + console.log('saveNewSubscriptionToServer') const userStore = useUserStore() diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json new file mode 100755 index 00000000..aa892b64 --- /dev/null +++ b/tsconfig.eslint.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": [ + // ... + "src-pwa/custom-service-worker.js" + ] +} diff --git a/tsconfig.json b/tsconfig.json index 05309215..e0cab9b9 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,9 +4,11 @@ // repeated from base config's "include" setting "src", "tests", + "src-pwa", + "public/js", // these are the eslint-only inclusions - ".eslintrc.js" + "**/*.config.js" // for *.config.js files ], "compilerOptions": { "experimentalDecorators": true, @@ -37,5 +39,8 @@ "model": ["src/model/index.ts"], "enums": ["src/enums/*"] } - } + }, + "exclude": [ + "node_modules" + ] }