{"id":18791953,"url":"https://github.com/wildhaber/offline-first-sw","last_synced_at":"2025-04-13T14:31:02.877Z","repository":{"id":43974901,"uuid":"84337127","full_name":"wildhaber/offline-first-sw","owner":"wildhaber","description":"Service worker example with 404 handling, custom offline page and max TTL for specific file types.","archived":false,"fork":false,"pushed_at":"2022-07-07T09:36:28.000Z","size":52,"stargazers_count":91,"open_issues_count":3,"forks_count":23,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-16T15:17:45.692Z","etag":null,"topics":["amp","example","offline-first","prefetch","pwa","service-worker","sw"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wildhaber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-08T15:40:24.000Z","updated_at":"2024-03-02T18:48:17.000Z","dependencies_parsed_at":"2022-07-11T00:46:20.692Z","dependency_job_id":null,"html_url":"https://github.com/wildhaber/offline-first-sw","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildhaber%2Foffline-first-sw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildhaber%2Foffline-first-sw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildhaber%2Foffline-first-sw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildhaber%2Foffline-first-sw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wildhaber","download_url":"https://codeload.github.com/wildhaber/offline-first-sw/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223589078,"owners_count":17169915,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amp","example","offline-first","prefetch","pwa","service-worker","sw"],"created_at":"2024-11-07T21:17:41.739Z","updated_at":"2024-11-07T21:17:43.649Z","avatar_url":"https://github.com/wildhaber.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Service Worker Example\n\n![offline first poster](https://github.com/wildhaber/offline-first-sw/blob/master/offline-first-sw.jpg \"offline first poster\")\n\n## Features\n\n - Custom offline page\n - Custom 404 page\n - Cache blacklist rules for resources that always comes from network\n - Individual TTL settings for different file extensions for a rolling cache refresh respecting offline-first \n - Easy to customize for your specific needs\n - Cleanup legacy cache on update\n - Automatic Caching of relative content defined with `\u003clink rel='index|next|prev|prefetch'\u003e`\n\n## Installation \u0026 Usage\n\n### Install the Service Worker\n\nSimply copy [**sw.js**](https://github.com/wildhaber/offline-first-sw/blob/master/sw.js) in your root directory:\n\n```shell\n# simple wget-snippet or do it manually\n# cd /your-projects-root-directory/\nwget https://raw.githubusercontent.com/wildhaber/offline-first-sw/master/sw.js\n```\n\nand launch the Service Worker with the following snippet:\n\n```js\n\u003cscript\u003e\n    if('serviceWorker' in navigator) {\n\n        /**\n         * Define if \u003clink rel='next|prev|prefetch'\u003e should\n         * be preloaded when accessing this page\n         */\n        const PREFETCH = true;\n\n        /**\n         * Define which link-rel's should be preloaded if enabled.\n         */\n        const PREFETCH_LINK_RELS = ['index','next', 'prev', 'prefetch'];\n\n        /**\n         * prefetchCache\n         */\n        function prefetchCache() {\n            if(navigator.serviceWorker.controller) {\n\n                let links = document.querySelectorAll(\n                    PREFETCH_LINK_RELS.map((rel) =\u003e {\n                        return 'link[rel='+rel+']';\n                    }).join(',')\n                );\n\n                if(links.length \u003e 0) {\n                    Array.from(links)\n                        .map((link) =\u003e {\n                            let href = link.getAttribute('href');\n                            navigator.serviceWorker.controller.postMessage({\n                                action : 'cache',\n                                url : href,\n                            });\n                        });\n                }\n\n\n            }\n        }\n\n        /**\n         * Register Service Worker\n         */\n        navigator.serviceWorker\n            .register('/sw.js', { scope: '/' })\n            .then(() =\u003e {\n                console.log('Service Worker Registered');\n            });\n\n        /**\n         * Wait if ServiceWorker is ready\n         */\n        navigator.serviceWorker\n            .ready\n            .then(() =\u003e {\n                if(PREFETCH) {\n                    prefetchCache();\n                }\n            });\n\n    }\n\u003c/script\u003e\n```\n\nFor AMP-Pages use:\n\n```html\n\u003cscript async custom-element=\"amp-install-serviceworker\" src=\"https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js\"\u003e\u003c/script\u003e\n```\n\n```html\n\u003camp-install-serviceworker\n\tsrc=\"/sw.js\"\n\tdata-iframe-src=\"https://ampbyexample.com/sw.html\"\n\tlayout=\"nodisplay\"\u003e\n\u003c/amp-install-serviceworker\u003e\n```\n\nGet more information for [AMP-Install-Serviceworker](https://ampbyexample.com/components/amp-install-serviceworker/) at [ampbyexample.com](https://ampbyexample.com/components/amp-install-serviceworker/)\n\n### Install the manifest.json\n\nThe manifest is an important part but not required. Read more about [manifest.json on Google Developers](https://developers.google.com/web/fundamentals/getting-started/codelabs/your-first-pwapp/).\n\nCopy the [**manifest.json**](https://github.com/wildhaber/offline-first-sw/blob/master/manifest.json) into your root directory and link it within your markup.\n\n```shell\n# simple wget-snippet or do it manually\n# cd /your-projects-root-directory/\nwget https://raw.githubusercontent.com/wildhaber/offline-first-sw/master/manifest.json\n```\n\nAnd create the following link-snippet within your page's `\u003chead\u003e`-Section:\n\n```html\n\u003clink rel=\"manifest\" href=\"/manifest.json\"\u003e\n```\n\n---\n\n## Configuration\n\n### Service Worker\n\n#### CACHE_VERSION `{ number }`\n\n```js\nconst CACHE_VERSION = 1;\n```\n\nThe CACHE_VERSION is important when you update your service-worker. The cache-location will be updated and the old legacy cache is getting deleted.\n\n#### BASE_CACHE_FILES  { array }\n\n```js\nconst BASE_CACHE_FILES = [\n    '/style.css',\n    '/script.js',\n    '/search.json',\n    '/manifest.json',\n    '/favicon.png',\n];\n```\nDefine files that in this list which always needs to be cached from the beginning.\n\n#### OFFLINE_CACHE_FILES  { array }\n\n```js\nconst OFFLINE_CACHE_FILES = [\n    '/style.css',\n    '/script.js',\n    '/offline/index.html',\n];\n```\n\nDefine files necessary for your offline page.\n\n#### NOT_FOUND_CACHE_FILES { array }\n\n```js\nconst NOT_FOUND_CACHE_FILES = [\n    '/style.css',\n    '/script.js',\n    '/404.html',\n];\n```\n\nDefine files necessary for your 404 page.\n\n#### OFFLINE_PAGE { string }\n\n```js\nconst OFFLINE_PAGE = '/offline/index.html';\n```\n\nDeliver this page when the user is offline and the page is not cached already.\n\n\n#### NOT_FOUND_PAGE { string }\n\n```js\nconst NOT_FOUND_PAGE = '/404.html';\n```\n\nDeliver this page when the user lands on a page with `Status-Code \u003e= 400`.\n\n#### MAX_TTL { object }\n\n```js\nconst MAX_TTL = {\n    '/': 3600,\n    html: 3600,\n    json: 86400,\n    js: 86400,\n    css: 86400,\n};\n```\n\nThis is a key-value mapping file extensions with a certain maximal time-to-live (**in seconds** not milliseconds). This is how long the chache will be active until the page is getting refreshed from the network.\n\nNot specified extensions with stay cached until a SW-Update.\n\n```js\n// 60 = 1 minute\n// 3600 = 1 hour\n// 86400 = 1 day\n// 604800 = 1 week\n// 2592000 = 30 days (~ 1 month)\n// 31536000 = 1 year\n```\n\n#### CACHE_BLACKLIST { array}\n\n```js\nconst CACHE_BLACKLIST = [\n    (str) =\u003e {\n\t    // str = URL of the resource\n\t    // apply this rule when you do not want to cache external files\n        return !str.startsWith('https://yourwebsite.tld');\n    },\n];\n```\n\nThis is a list of functions a `URL` gets checked against if it should be cached or not. If one method returns `true` this resource will not be cached.\n\n#### SUPPORTED_METHODS { array }\n\n```js\nconst SUPPORTED_METHODS = [\n    'GET',\n];\n```\n\nOnly methods in this list will be cached.\n\n---\n\n## MIT License\n\nCopyright (c) 2017 Raphael Wildhaber, https://github.com/wildhaber/\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwildhaber%2Foffline-first-sw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwildhaber%2Foffline-first-sw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwildhaber%2Foffline-first-sw/lists"}