From b3e8e2a5df97db9fc7f592f2e8873b99bc7fdcb5 Mon Sep 17 00:00:00 2001 From: Jinksi Date: Wed, 5 Jul 2017 21:07:57 +1000 Subject: [PATCH] Custom SW config --- package.json | 6 +- src/index.js | 3 + src/registerServiceWorker.js | 108 +++++++++++++++++++++++++++++++++++ sw-precache-config.js | 23 ++++++++ yarn.lock | 2 +- 5 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 src/registerServiceWorker.js create mode 100644 sw-precache-config.js diff --git a/package.json b/package.json index 20e38ea..24083f0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "devDependencies": { "react-scripts": "^1.0.10", "snazzy": "^7.0.0", - "standard": "^10.0.2" + "standard": "^10.0.2", + "sw-precache": "^5.2.0" }, "dependencies": { "polished": "^1.2.1", @@ -19,7 +20,8 @@ }, "scripts": { "start": "react-scripts start", - "build": "react-scripts build && react-snapshot", + "build": "react-scripts build && react-snapshot && npm run sw", + "sw": "sw-precache --config='sw-precache-config.js'", "test": "standard | snazzy && react-scripts test --env=jsdom", "eject": "react-scripts eject" }, diff --git a/src/index.js b/src/index.js index 70af592..b34a9f7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import React from 'react' import { render } from 'react-snapshot' import App from './App' +import registerServiceWorker from './registerServiceWorker' const rootEl = document.getElementById('root') render(, rootEl) @@ -11,3 +12,5 @@ if (module.hot) { render(, rootEl) }) } + +registerServiceWorker() diff --git a/src/registerServiceWorker.js b/src/registerServiceWorker.js new file mode 100644 index 0000000..e907b6f --- /dev/null +++ b/src/registerServiceWorker.js @@ -0,0 +1,108 @@ +// In production, we register a service worker to serve assets from local cache. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on the "N+1" visit to a page, since previously +// cached resources are updated in the background. + +// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. +// This link also includes instructions on opting out of this behavior. + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +) + +export default function register () { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location) + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets see https://github.com/facebookincubator/create-react-app/issues/2374 + return + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` + + if (!isLocalhost) { + // Is not local host. Just register service worker + registerValidSW(swUrl) + } else { + // This is running on localhost. Lets check if a service worker still exists or not. + checkValidServiceWorker(swUrl) + } + }) + } +} + +function registerValidSW (swUrl) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the old content will have been purged and + // the fresh content will have been added to the cache. + // It's the perfect time to display a "New content is + // available please refresh." message in your web app. + console.log('New content is available; please refresh.') + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.') + } + } + } + } + }) + .catch(error => { + console.error('Error during service worker registration:', error) + }) +} + +function checkValidServiceWorker (swUrl) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + if ( + response.status === 404 || + response.headers.get('content-type').indexOf('javascript') === -1 + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload() + }) + }) + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl) + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ) + }) +} + +export function unregister () { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister() + }) + } +} diff --git a/sw-precache-config.js b/sw-precache-config.js new file mode 100644 index 0000000..b94e88e --- /dev/null +++ b/sw-precache-config.js @@ -0,0 +1,23 @@ +// we overwrite the default service worker config to enable runtimeCaching +module.exports = { + stripPrefix: 'build/', + staticFileGlobs: [ + 'build/**/*.html', + 'build/*.svg', + 'build/*.jpg', + 'build/*.png', + 'build/*.ico', + 'build/*.json', + 'build/static/**/!(*map*)', + 'build/manifest.json' + ], + dontCacheBustUrlsMatching: /\.\w{8}\./, + swFilePath: 'build/service-worker.js', + // any external urls you wish to cache (e.g. CDN) + runtimeCaching: [ + { + urlPattern: /^https?:\/\/.*example-cdn.com/, + handler: 'cacheFirst' + } + ] +} diff --git a/yarn.lock b/yarn.lock index 0f933ab..aa349fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6189,7 +6189,7 @@ sw-precache-webpack-plugin@0.11.3: sw-precache "^5.1.1" uglify-js "^3.0.13" -sw-precache@^5.1.1: +sw-precache@^5.1.1, sw-precache@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/sw-precache/-/sw-precache-5.2.0.tgz#eb6225ce580ceaae148194578a0ad01ab7ea199c" dependencies: