{"id":760,"date":"2022-09-23T14:41:55","date_gmt":"2022-09-23T14:41:55","guid":{"rendered":"http:\/\/wp.chaoyu.nl\/?p=760"},"modified":"2022-09-23T17:15:11","modified_gmt":"2022-09-23T17:15:11","slug":"pwa-in-oracle-apex","status":"publish","type":"post","link":"https:\/\/chaoyu.nl\/?p=760","title":{"rendered":"PWA in Oracle APEX"},"content":{"rendered":"\n<ul class=\"wp-block-list\"><li><strong>Serve your application with offline content<\/strong><\/li><li><strong>Web Push notifications<\/strong><\/li><li><strong>Sync to handle offline User DML request( REST API only)<\/strong><\/li><\/ul>\n\n\n\n<blockquote class=\"wp-block-quote has-light-green-cyan-background-color has-background is-layout-flow wp-block-quote-is-layout-flow\"><p><strong>Serve your application with offline content when network is down. Serve server rendered html when network is up. <\/strong><\/p><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">serve your application with offline caches via Fetch event ( fetch event fires each time a request is sent to the server), what we do here is tapping into the web page request, download all requested resouces used for browser to render a page and eventually store them into cache use cache api. I named as test. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code lang=\"javascript\" class=\"language-javascript line-numbers\">self.addEventListener(\"fetch\", (event) =&gt; {\n  \/\/ \"fetch\" hook starts\n  event.respondWith(\n    (async () =&gt; {\n      let cacheName = \"test\";\n      let cache;\n      \/\/ Try to get from the cache first\n      if (cacheName) {\n        cache = await caches.open(cacheName);\n        \/\/ for html I always want to get from server unless there is no network\n        if (event.request.url.indexOf(\"session=\") &lt; 0) {\n          const response = await cache.match(event.request);\n          if (response) {\n            return response;\n          }\n        }\n      }\n      \/\/ Then get from network\n      try {\n        const response = await fetch(event.request);\n        if (response.ok &amp;&amp; cacheName) {\n          try {\n            const resClone = response.clone();\n            cache.put(event.request, resClone);\n          } catch (error) {\n            console.warn(error);\n          }\n        }\n        \/\/ Return resource from network\n        return response;\n      } catch (error) {\n         \/\/ for apex page where i do have cache , i serve the cache\n        const response = await cache.match(event.request);\n        if (response) {\n          return response;\n        } else {\n           \/\/ for apex page where i DO NOT have cache, i serve dummy html \n          if (event.request.mode === \"navigate\") {\n            const offlinePage =\n              '&lt;div style=\"height:100%;text-align:center; font-size:30px;padding-top: 50%;\"&gt; Your Device Is Offline &lt;\/div&gt;';\n            return new Response(offlinePage, {\n              headers: { \"Content-Type\": \"text\/html\" },\n            });\n          } else {\n            return new Response();\n          }\n        }\n      }\n    })()\n  );\n});\n<\/code><\/pre>\n\n\n\n<pre title=\"Default APEX Fetch settings\" class=\"wp-block-code has-small-font-size\"><code lang=\"javascript\" class=\"language-javascript line-numbers\">let apex = {};\napex.sw = {};\napex.sw.CORE_CACHE_MATCHER = '#APEX_FILES#';\napex.sw.CORE_CACHE_PREFIX = \"APEX-CORE-\";\napex.sw.CORE_CACHE_NAME = apex.sw.CORE_CACHE_PREFIX + '#APEX_VERSION#';\n\napex.sw.APP_CACHE_MATCHER = \"&amp;FB_FLOW_ID.\/files\/static\/v\";\napex.sw.APP_CACHE_PREFIX = \"APEX-APP-&amp;FB_FLOW_ID.-v\";\n\napex.sw.appCacheNeedsCleanup = true;\n\napex.sw.cleanAPEXCaches = () =&gt; {\n  caches.keys().then(cacheNames =&gt; Promise.all(\n    cacheNames.map(cacheName =&gt; {\n      if (cacheName.startsWith(apex.sw.CORE_CACHE_PREFIX) &amp;&amp; cacheName !== apex.sw.CORE_CACHE_NAME) {\n        return caches.delete(cacheName);\n      }\n    })\n  ));\n};\n\napex.sw.cleanAppCaches = (appCacheName) =&gt; {\n  if (appCacheNeedsCleanup) {\n    appCacheNeedsCleanup = false;\n    caches.keys().then(cacheNames =&gt; Promise.all(\n      cacheNames.map(cacheName =&gt; {\n        if (cacheName.startsWith(apex.sw.APP_CACHE_PREFIX) &amp;&amp; cacheName !== appCacheName) {\n          return caches.delete(cacheName);\n        }\n      })\n    ));\n  }\n};\n\n\n\nself.addEventListener(\"fetch\", (event) =&gt; {\n  event.respondWith(\n    (async () =&gt; {\n      let cacheName;\n      if (\n        event.request &amp;&amp;\n        event.request.url &amp;&amp;\n        event.request.url.indexOf(apex.sw.CORE_CACHE_MATCHER) &gt;= 0\n      ) {\n        cacheName = apex.sw.CORE_CACHE_NAME;\n      } else if (\n        event.request &amp;&amp;\n        event.request.url &amp;&amp;\n        event.request.url.indexOf(apex.sw.APP_CACHE_MATCHER) &gt;= 0\n      ) {\n        const fileVersion = event.request.url\n          .split(apex.sw.APP_CACHE_MATCHER)\n          .pop()\n          .split(\"\/\")[0];\n        cacheName = apex.sw.APP_CACHE_PREFIX + fileVersion;\n        apex.sw.cleanAppCaches(cacheName);\n      }\n      let cache;\n      \/\/ Try to get from the cache first\n      if (cacheName) {\n        cache = await caches.open(cacheName);\n        const response = await cache.match(event.request);\n        if (response) {\n          return response;\n        }\n      }\n      \/\/ Then get from network\n      try {\n        const response = await fetch(event.request);\n        \/\/ Clone response to put in cache\n        if (response.ok &amp;&amp; cacheName) {\n          try {\n            const resClone = response.clone();\n            cache.put(event.request, resClone);\n          } catch (error) {\n            console.warn(error);\n          }\n        }\n        \/\/ Return ressource from network\n        return response;\n      } catch (error) {\n        if (event.request.mode === \"navigate\") {\n          const offlinePage = \"APEX.PWA.OFFLINE\";\n          return new Response(offlinePage, {\n            headers: { \"Content-Type\": \"text\/html\" },\n          });\n        } else {\n          return new Response();\n        }\n      }\n    })()\n  );\n});\n<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote has-vivid-green-cyan-background-color has-background is-layout-flow wp-block-quote-is-layout-flow\"><p><strong>Web Push Notifications<\/strong><\/p><cite>using firebase<\/cite><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Serve your application with offline content Web Push notifications Sync to handle offline User DML request( REST API only) Serve your application with offline content when network is down. Serve server rendered html when network is up. serve your application with offline caches via Fetch event ( fetch event fires each time a request is&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-760","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/chaoyu.nl\/index.php?rest_route=\/wp\/v2\/posts\/760","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chaoyu.nl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/chaoyu.nl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/chaoyu.nl\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chaoyu.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=760"}],"version-history":[{"count":24,"href":"https:\/\/chaoyu.nl\/index.php?rest_route=\/wp\/v2\/posts\/760\/revisions"}],"predecessor-version":[{"id":785,"href":"https:\/\/chaoyu.nl\/index.php?rest_route=\/wp\/v2\/posts\/760\/revisions\/785"}],"wp:attachment":[{"href":"https:\/\/chaoyu.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=760"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/chaoyu.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=760"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chaoyu.nl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=760"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}