sw.js.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <?php
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. define('BX_SERVICE_WORKER', true);
  10. require_once('./inc/header.inc.php');
  11. $oTemplate = BxDolTemplate::getInstance();
  12. $sCacheName = 'app' . $oTemplate->getRevision();
  13. $aAssets = [];
  14. //--- CSS/JS files
  15. foreach(['css' , 'js'] as $sType) {
  16. $aFiles = $oTemplate->includeFiles($sType, true, false);
  17. if(!is_array($aFiles))
  18. $aFiles = [$aFiles];
  19. $aAssets = array_merge($aAssets, $aFiles);
  20. }
  21. if(($sCache = getParam('sys_pwa_sw_cache')) != '') {
  22. $aItems = preg_split("/\\r\\n|\\r|\\n/", $sCache);
  23. if(!empty($aItems) && is_array($aItems))
  24. foreach($aItems as $sItem) {
  25. if(strpos($sItem, BX_DOL_URL_ROOT) === false)
  26. $sItem = BX_DOL_URL_ROOT . $sItem;
  27. $aAssets[] = $oTemplate->addRevision($sItem);
  28. }
  29. }
  30. //--- Offline page
  31. $sOffline = '';
  32. if(($sOffline = getParam('sys_pwa_sw_offline')) != '') {
  33. $sOffline = BX_DOL_URL_ROOT . $sOffline;
  34. $aAssets[] = $sOffline;
  35. }
  36. //--- Favicon or SVG icon
  37. $sIconUrl = '';
  38. if(($iId = (int)getParam('sys_site_icon')) != 0)
  39. $sIconUrl = BxDolStorage::getObjectInstance(BX_DOL_STORAGE_OBJ_FILES)->getFileUrlById($iId);
  40. if(!$sIconUrl && ($iId = (int)getParam('sys_site_icon_svg')) != 0)
  41. $sIconUrl = BxDolStorage::getObjectInstance(BX_DOL_STORAGE_OBJ_IMAGES)->getFileUrlById($iId);
  42. if(!empty($sIconUrl))
  43. $aAssets[] = $sIconUrl;
  44. //--- Fonts
  45. if(getParam('sys_css_icons_default') != '') {
  46. $sHomeUrl = BX_DOL_URL_ROOT;
  47. if(BxDolModuleQuery::getInstance()->isEnabledByName('bx_fontawesome'))
  48. $sHomeUrl = BxDolModule::getInstance('bx_fontawesome')->_oConfig->getHomeUrl();
  49. $aAssets[] = $sHomeUrl . 'template/fonts/fa-solid-900.woff2';
  50. $aAssets[] = $sHomeUrl . 'template/fonts/fa-regular-400.woff2';
  51. }
  52. header("Content-Type: text/javascript");
  53. ?>
  54. // Core assets
  55. let coreAssets = <?php echo json_encode($aAssets); ?>;
  56. // On install, cache core assets
  57. self.addEventListener('install', function (event) {
  58. // Cache core assets
  59. event.waitUntil((async () => {
  60. caches.open('<?php echo $sCacheName; ?>').then(function (cache) {
  61. for (let asset of coreAssets) {
  62. cache.add(new Request(asset));
  63. }
  64. return cache;
  65. });
  66. })());
  67. });
  68. const deleteCache = async (key) => {
  69. await caches.delete(key);
  70. };
  71. const deleteOldCaches = async () => {
  72. const cacheKeepList = ["<?php echo $sCacheName; ?>"];
  73. const keyList = await caches.keys();
  74. const cachesToDelete = keyList.filter((key) => !cacheKeepList.includes(key));
  75. await Promise.all(cachesToDelete.map(deleteCache));
  76. };
  77. // delete old cache on activate
  78. self.addEventListener("activate", (event) => {
  79. event.waitUntil(deleteOldCaches());
  80. });
  81. // Listen for request events
  82. self.addEventListener('fetch', function (event) {
  83. // Get the request
  84. let request = event.request;
  85. // Bug fix
  86. // https://stackoverflow.com/a/49719964
  87. if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') return;
  88. // regular pages and static assets
  89. if (request.mode === 'navigate' || request.url.match(/\.(css|js|woff2|svg|png|jpg)$/)) {
  90. const failedResponse = async (err) => {
  91. let reponse = null;
  92. const sOfflinePage = '<?php echo $sOffline; ?>';
  93. if (request.mode === 'navigate' && sOfflinePage.length != 0) {
  94. const cache = await caches.open('<?php echo $sCacheName; ?>');
  95. reponse = await cache.match(sOfflinePage);
  96. }
  97. return reponse || new Response("Network error happened", {
  98. status: 408,
  99. headers: { "Content-Type": "text/plain" },
  100. });
  101. }
  102. event.respondWith(
  103. caches.match(request).then((response) => {
  104. try {
  105. return response || fetch(request)
  106. .then((response) => {
  107. return response;
  108. })
  109. .catch((err) => {
  110. return failedResponse(err);
  111. });
  112. } catch (error) {
  113. return failedResponse(err);
  114. }
  115. })
  116. );
  117. }
  118. });