Fork of the official gatsby-plugin-offline with updated workbox version. Based on this PR.
Thus consider the status of this plugin currently as somewhat unstable (in the sense that if the above mentioned case happens, users will probably need to switch back to the official plugin, which however should not be a big deal, but nonetheless something you should keep in mind if you're using this fork).
Adds drop-in support for making a Gatsby site work offline and more resistant to bad network connections. It uses workbox-webpack-plugin to create a service worker for the site and loads the service worker into the client.
If you're using this plugin with gatsby-plugin-manifest
(recommended) this
plugin should be listed after that plugin so the manifest file can be included
in the service worker.
npm install gatsby-plugin-offline-next
// In your gatsby-config.js
plugins: [`gatsby-plugin-offline-next`]
In gatsby-plugin-offline-next
5.x, the following options are available:
-
precachePages
lets you specify pages whose resources should be precached by the service worker, using an array of globs. For example:plugins: [ { resolve: `gatsby-plugin-offline-next`, options: { precachePages: [`/about-us/`, `/projects/*`], }, }, ]
Note: while essential resources of specified pages will be precached, such as JavaScript and CSS, non-essential resources such as fonts and images will not be included. Instead, these will be cached at runtime when a user visits a given page that includes these resources.
-
swSrc
lets you specify a file that is used as the entry point of the service worker (sw.js
). For example:plugins: [ { resolve: `gatsby-plugin-offline-next`, options: { swSrc: require.resolve(`src/custom-sw-code.js`), }, }, ]
// default workbox setup & logic from `gatsby-plugin-offline-next/serviceworker/index.js`: import { precache } from "gatsby-plugin-offline-next/serviceworker/precache.js" import { setup } from "gatsby-plugin-offline-next/serviceworker/setup.js" import { registerDefaultRoutes } from "gatsby-plugin-offline-next/serviceworker/default-routes.js" import { setupOfflineRouting } from "gatsby-plugin-offline-next/serviceworker/offline.js" import { googleAnalytics } from "gatsby-plugin-offline-next/serviceworker/google-analytics.js" import { cleanup } from "gatsby-plugin-offline-next/serviceworker/cleanup.js" import { NavigationRoute, registerRoute } from "workbox-routing" precache() setup() registerDefaultRoutes() setupOfflineRouting() googleAnalytics() cleanup() // custom code: // show a notification after 15 seconds (the notification // permission must be granted first) setTimeout(() => { self.registration.showNotification("Hello, world!") }, 15000) // register a custom navigation route const customRoute = new NavigationRoute(({ event }) => { // ... }) registerRoute(customRoute)
The specified file will be compiled/bundled with webpack, so as shown in the example above, other modules can be imported.
Note: if you provide the
swSrc
option, you'll need to make sure that the appropriate workbox routes get set up and also the custom offline logic this plugin provides gets executed. See files ingatsby-plugin-offline-next/serviceworker
for further information -
cacheId
lets you specify a custom cache prefix used by workbox. See Configure Workbox Documentation -
define
Object passed to webpacks DefinePlugin to define values that get replaced in the compiled service worker. See DefinePlugin -
webpackCompilationPlugins
Optional webpack plugins that will be used when compiling the swSrc input file. See InjectManifest options -
chunks
additional webpack chunk names that shall be precached. See InjectManifest for more information -
offlineAnalyticsConfig
If specified, these options get passed to the workbox-google-analytics plugin. You can also set this option to just enable this plugin with the default options -
deletePreviousCacheVersionsOnUpdate
If set to true, automatically attempts to delete previous caches on service worker update ifcacheId
has changed. Useful if you'rechacheId
might change, and you want to avoid old, unused caches form taking up space on the user's device. -
cleanupOutdatedCaches
If set to true, automatically cleans up outdated caches from older workbox versions. See workbox's documentation -
globPatterns
A set of optional glob patterns to include in precaching. -
lodashWebpackPluginFeatures
Configuration of enabled lodash feature sets. See lodash-webpack-plugin -
additionalManifestEntries
,manifestTransforms
,maximumFileSizeToCacheInBytes
,dontCacheBustURLsMatching
,modifyURLPrefix
Options passed to workbox's InjectManifest webpack plugin
Version 5.x of this plugin no longer uses the workbox-build
/generateSW
tool to generate the service worker.
Instead, it uses the InjectManifest
webpack plugin.
This means that some options are no longer supported (although it should be possible to implement the same features via a custom swSrc
-> see above).
To upgrade from a version prior to 5.x (3.x, 4.x) of the official gatsby-plugin-offline
, you'll need to perform the following steps:
-
Remove no longer supported options
importWorkboxFrom
andglobDirectory
-
Move supported options from
workboxConfig
to the root level option object
// previous
plugins: [
{
resolve: `gatsby-plugin-offline`,
options: {
precachePages: ["about"],
workboxConfig: {
cacheId: "some-cache-id",
offlineGoogleAnalytics: true,
cleanupOutdatedCaches: true,
directoryIndex: "index.html",
importWorkboxFrom: "cdn",
},
},
},
]
// v5 (gatsby-plugin-offline-next)
plugins: [
{
resolve: `gatsby-plugin-offline-next`,
options: {
precachePages: ["about"],
cacheId: "some-cache-id",
offlineGoogleAnalytics: true,
cleanupOutdatedCaches: true,
directoryIndex: "index.html",
},
},
]
-
The
runtimeCaching
option is no longer supported in 5.x. If you previously used customruntimeCaching
handlers, you'll need to create a customswSrc
file to archive the same effect.
In case you just added some additional handlers without modifying the default handlers provided by
gatsby-plugin-offline
, this should be straight forward:
// previous
plugins: [
{
resolve: `gatsby-plugin-offline`,
options: {
workboxConfig: {
runtimeCaching: [
// Default handlers from gatsby-plugin-offline
{
// Use cacheFirst since these don't need to be revalidated (same RegExp
// and same reason as above)
urlPattern: /(\.js$|\.css$|static\/)/,
handler: `CacheFirst`,
},
{
// page-data.json files, static query results and app-data.json
// are not content hashed
urlPattern: /^https?:.*\/page-data\/.*\.json/,
handler: `StaleWhileRevalidate`,
},
{
// Add runtime caching of various other page resources
urlPattern: /^https?:.*\.(png|jpg|jpeg|webp|avif|svg|gif|tiff|js|woff|woff2|json|css)$/,
handler: `StaleWhileRevalidate`,
},
{
// Google Fonts CSS (doesn't end in .css so we need to specify it)
urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/,
handler: `StaleWhileRevalidate`,
},
// Your custom handler
{
urlPattern: /my-custom-pattern/,
handler: `NetworkFirst`,
},
],
},
},
},
]
// 5.x (gatsby-plugin-offline-next)
plugins: [
{
resolve: `gatsby-plugin-offline-next`,
options: {
// ...
swSrc: path.resolve(__dirname, "src/custom-sw.js"),
},
},
]
// this includes the default behaviour & setup of the service worker from gatsby-plugin-offline
import "gatsby-plugin-offline-next/serviceworker/index.js"
import { registerRoute } from "workbox-routing"
import { NetworkFirst } from "workbox-strategies"
// your custom handler goes here
registerRoute(/my-custom-pattern/, new NetworkFirst(), `GET`)
If you have previously overwritten or modified the default handlers from gatsby-plugin-offline
, you'll need a bit more code in your swSrc
:
// previous
plugins: [
{
resolve: `gatsby-plugin-offline`,
options: {
workboxConfig: {
runtimeCaching: [
// Default handlers from gatsby-plugin-offline
{
// *modified*
// Use cacheFirst since these don't need to be revalidated (same RegExp
// and same reason as above)
urlPattern: /(\.js$|\.css$|static\/|\.wasm$)/,
handler: `StaleWhileRevalidate`,
},
{
// *not modified*
// page-data.json files, static query results and app-data.json
// are not content hashed
urlPattern: /^https?:.*\/page-data\/.*\.json/,
handler: `StaleWhileRevalidate`,
},
],
},
},
},
]
// 5.x (gatsby-plugin-offline-next)
plugins: [
{
resolve: `gatsby-plugin-offline-next`,
options: {
// ...
swSrc: path.resolve(__dirname, "src/custom-sw.js"),
},
},
]
// code based on gatsby-plugin-offline-next/serviceworker/index.js (note: `registerDefaultRoutes()` is not used, as we will define all used route handlers below ourselfs)
import { precache } from "gatsby-plugin-offline-next/serviceworker/precache.js"
import { setup } from "gatsby-plugin-offline-next/serviceworker/setup.js"
import { setupOfflineRouting } from "gatsby-plugin-offline-next/serviceworker/offline.js"
import { googleAnalytics } from "gatsby-plugin-offline-next/serviceworker/google-analytics.js"
import { cleanup } from "gatsby-plugin-offline-next/serviceworker/cleanup.js"
import { NavigationRoute, registerRoute } from "workbox-routing"
import { registerRoute } from "workbox-routing"
import { StaleWhileRevalidate } from "workbox-strategies"
precache()
setup()
setupOfflineRouting()
googleAnalytics()
cleanup()
// your custom/modified handlers go here. Note: you'll need to specify all handlers manually, even those you didn't modify previously
registerRoute(
/(\.js$|\.css$|static\/|\.wasm$)/,
new StaleWhileRevalidate(),
`GET`
) // modified handler
registerRoute(
/^https?:.*\/page-data\/.*\.json/,
new StaleWhileRevalidate(),
`GET`
) // unmodified default handler
If you want to remove gatsby-plugin-offline-next
from your site at a later point,
substitute it with gatsby-plugin-remove-serviceworker
to safely remove the service worker. First, install the new package:
npm install gatsby-plugin-remove-serviceworker
npm uninstall gatsby-plugin-offline-next
Then, update your gatsby-config.js
:
plugins: [
- `gatsby-plugin-offline-next`,
`gatsby-plugin-remove-serviceworker`,
]
This will ensure that the worker is properly unregistered, instead of leaving an outdated version registered in users' browsers.
Gatsby offers great SEO capabilities and that is no different with gatsby-plugin-offline-next
. However, you shouldn't think that Gatsby doesn't serve HTML tags anymore when looking at your source code in the browser (with Right click
=> View source
). View source
doesn't represent the actual HTML data since gatsby-plugin-offline-next
registers and loads a service worker that will cache and handle this differently. Your site is loaded from the service worker, not from its actual source (check your Network
tab in the DevTools for that).
To see the HTML data that crawlers will receive, run this in your terminal:
on Windows (using powershell):
Invoke-WebRequest https://www.yourdomain.tld | Select -ExpandProperty Content
on Mac OS/Linux:
curl https://www.yourdomain.tld
Alternatively you can have a look at the /public/index.html
file in your project folder.
Server logs (like from Netlify analytics) may show a large number of pageviews to a route like /offline-plugin-app-shell-fallback/index.html
, this is a result of gatsby-plugin-offline-next
adding an app shell to the page. The app shell is a minimal amount of user interface that can be cached offline for reliable performance loading on repeat visits. The shell can be loaded from the cache, and the content of the site loaded into the shell by the service worker.
If using this plugin with gatsby-plugin-manifest
you may find that your icons are not cached.
In order to solve this, update your gatsby-config.js
as follows:
// gatsby-config.js
{
resolve: 'gatsby-plugin-manifest',
options: {
icon: 'icon.svg',
cache_busting_mode: 'none'
}
},
{
resolve: 'gatsby-plugin-offline-next',
options: {
workboxConfig: {
globPatterns: ['**/icon-path*']
}
}
}
Updating cache_busting_mode
is necessary. Otherwise, workbox will break while attempting to find the cached URLs.
Adding the globPatterns
makes sure that the offline plugin will cache everything.
Note that you have to prefix your icon with icon-path
or whatever you may call it