gatsby-plugin-offline-next v5.2.3
gatsby-plugin-offline-next
Fork of the official gatsby-plugin-offline with updated workbox version. Based on this PR.
⚠️ Note: I created this fork of the above mentioned PR because the PR currently does not seem to get any feedback, and I wanted to provide the plugin with a more recent version of workbox to users who need/want it. If the Gatsby team decides to merge the above mentioned PR, this plugin will be obsolete and the official plugin should be used again.
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).
Description
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.
Install
npm install gatsby-plugin-offline-next
How to use
// In your gatsby-config.js
plugins: [`gatsby-plugin-offline-next`]Available options
In gatsby-plugin-offline-next 5.x, the following options are available:
precachePageslets 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.
swSrclets 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
swSrcoption, 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/serviceworkerfor further informationcacheIdlets you specify a custom cache prefix used by workbox. See Configure Workbox DocumentationdefineObject passed to webpacks DefinePlugin to define values that get replaced in the compiled service worker. See DefinePluginwebpackCompilationPluginsOptional webpack plugins that will be used when compiling the swSrc input file. See InjectManifest optionschunksadditional webpack chunk names that shall be precached. See InjectManifest for more informationofflineAnalyticsConfigIf 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 optionsdeletePreviousCacheVersionsOnUpdateIf set to true, automatically attempts to delete previous caches on service worker update ifcacheIdhas changed. Useful if you'rechacheIdmight change, and you want to avoid old, unused caches form taking up space on the user's device.cleanupOutdatedCachesIf set to true, automatically cleans up outdated caches from older workbox versions. See workbox's documentationglobPatternsA set of optional glob patterns to include in precaching.lodashWebpackPluginFeaturesConfiguration of enabled lodash feature sets. See lodash-webpack-pluginadditionalManifestEntries,manifestTransforms,maximumFileSizeToCacheInBytes,dontCacheBustURLsMatching,modifyURLPrefixOptions passed to workbox's InjectManifest webpack plugin
Migrating from official gatsby-plugin-offline (v4.x)
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
importWorkboxFromandglobDirectoryMove supported options from
workboxConfigto 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
runtimeCachingoption is no longer supported in 5.x. If you previously used customruntimeCachinghandlers, you'll need to create a customswSrcfile 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 handlerRemove
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-nextThen, 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.
Notes
Empty View Source and SEO
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 Contenton Mac OS/Linux:
curl https://www.yourdomain.tldAlternatively you can have a look at the /public/index.html file in your project folder.
App shell and server logs
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.
Using with gatsby-plugin-manifest
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