Top Related Projects
📦 Workbox: JavaScript libraries for Progressive Web Apps
make your Next.js application work offline using service workers via Google's workbox
❤️ JavaScript/TypeScript linter (ESLint wrapper) with great defaults
The React Framework
✈️ Easily create sites that work offline as well as online
Webpack plugin that generates a service worker using sw-precache that will cache webpack's bundles' emitted assets. You can optionally pass sw-precache configuration options to webpack through this plugin.
Quick Overview
Next-pwa is a zero-config Progressive Web App (PWA) plugin for Next.js. It simplifies the process of adding PWA functionality to Next.js applications, enabling features like offline support, app installation, and push notifications with minimal setup.
Pros
- Zero configuration required for basic PWA functionality
- Seamless integration with Next.js projects
- Automatic generation of service worker and manifest files
- Customizable options for advanced use cases
Cons
- Limited documentation for complex scenarios
- May require additional configuration for specific PWA features
- Potential conflicts with other Next.js plugins or custom service workers
- Dependency on Next.js framework limits its use in other React projects
Code Examples
- Basic usage in
next.config.js
:
const withPWA = require('next-pwa')({
dest: 'public'
})
module.exports = withPWA({
// Your Next.js config
})
- Custom runtime caching:
const withPWA = require('next-pwa')({
dest: 'public',
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.example\.com\/.*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 50,
maxAgeSeconds: 60 * 60 * 24 // 1 day
}
}
}
]
})
- Disabling PWA in development:
const withPWA = require('next-pwa')({
dest: 'public',
disable: process.env.NODE_ENV === 'development'
})
Getting Started
-
Install the package:
npm install next-pwa
-
Add the plugin to your
next.config.js
:const withPWA = require('next-pwa')({ dest: 'public' }) module.exports = withPWA({ // Your Next.js config })
-
Create a
manifest.json
file in yourpublic
directory with your PWA details. -
Add the following to your
_document.js
or_app.js
:<link rel="manifest" href="/manifest.json" />
-
Build and run your Next.js application as usual.
Competitor Comparisons
📦 Workbox: JavaScript libraries for Progressive Web Apps
Pros of Workbox
- More comprehensive and flexible PWA toolset
- Extensive documentation and community support
- Broader range of caching strategies and offline capabilities
Cons of Workbox
- Steeper learning curve for beginners
- Requires more configuration and setup compared to Next PWA
- May be overkill for simpler PWA projects
Code Comparison
Workbox:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js');
workbox.routing.registerRoute(
({request}) => request.destination === 'image',
new workbox.strategies.CacheFirst()
);
Next PWA:
const withPWA = require('next-pwa')({
dest: 'public',
register: true,
skipWaiting: true,
});
module.exports = withPWA({
// your Next.js config
});
Summary
Workbox offers a more powerful and flexible solution for building PWAs, with extensive features and caching strategies. However, it comes with a steeper learning curve and requires more setup. Next PWA, on the other hand, provides a simpler integration for Next.js projects, making it easier to get started with PWAs in a Next.js environment. The choice between the two depends on the project's complexity and specific requirements.
make your Next.js application work offline using service workers via Google's workbox
Pros of next-offline
- Simpler setup and configuration process
- Better integration with Next.js routing system
- More customizable service worker generation
Cons of next-offline
- Less actively maintained (last update over 2 years ago)
- Fewer features and options compared to next-pwa
- Limited documentation and examples
Code Comparison
next-offline configuration:
const withOffline = require('next-offline')
module.exports = withOffline({
workboxOpts: {
swDest: 'static/service-worker.js',
runtimeCaching: [
// Custom runtime caching rules
],
},
})
next-pwa configuration:
const withPWA = require('next-pwa')
module.exports = withPWA({
pwa: {
dest: 'public',
register: true,
skipWaiting: true,
disable: process.env.NODE_ENV === 'development',
},
})
Both libraries aim to add Progressive Web App (PWA) functionality to Next.js applications, but they differ in their approach and feature set. next-offline provides a more straightforward setup but with fewer options, while next-pwa offers more comprehensive features and active maintenance. The choice between the two depends on the specific requirements of your project and the level of customization needed for your PWA implementation.
❤️ JavaScript/TypeScript linter (ESLint wrapper) with great defaults
Pros of xo
- Broader scope: xo is a JavaScript/TypeScript linter and formatter, while next-pwa focuses specifically on PWA functionality for Next.js
- More customizable: xo offers extensive configuration options for linting rules and code style preferences
- Active development: xo has more recent updates and a larger community of contributors
Cons of xo
- Steeper learning curve: xo's extensive configuration options may require more time to set up and customize
- Less specialized: xo doesn't provide specific PWA features like next-pwa does for Next.js applications
Code Comparison
xo (linting and formatting):
// xo.config.js
module.exports = {
space: 2,
semicolon: false,
rules: {
'no-unused-vars': 'error'
}
}
next-pwa (PWA configuration):
// next.config.js
const withPWA = require('next-pwa')({
dest: 'public',
register: true,
skipWaiting: true
})
module.exports = withPWA({
// your Next.js config
})
While both repositories serve different purposes, xo provides a more general-purpose tool for code quality, while next-pwa offers specialized functionality for creating Progressive Web Apps with Next.js. The choice between them depends on the specific needs of your project.
The React Framework
Pros of Next.js
- Comprehensive full-stack React framework with built-in routing, server-side rendering, and API routes
- Large ecosystem and community support, with extensive documentation and resources
- Seamless integration with Vercel's deployment platform for optimal performance
Cons of Next.js
- Steeper learning curve for developers new to server-side rendering concepts
- Less focused on Progressive Web App (PWA) features out of the box
- Potentially more complex setup for simple static sites
Code Comparison
Next.js (pages/index.js):
import Head from 'next/head'
export default function Home() {
return (
<div>
<Head>
<title>My Next.js App</title>
</Head>
<h1>Welcome to Next.js!</h1>
</div>
)
}
Next-pwa (pages/_app.js):
import Head from 'next/head'
import { useEffect } from 'react'
function MyApp({ Component, pageProps }) {
useEffect(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
}, [])
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<Component {...pageProps} />
</>
)
}
export default MyApp
✈️ Easily create sites that work offline as well as online
Pros of UpUp
- Lightweight and easy to implement, with a simple API
- Focuses specifically on offline functionality and content caching
- Works with any web technology stack, not tied to a specific framework
Cons of UpUp
- Less actively maintained compared to next-pwa
- Limited features beyond basic offline functionality
- May require more manual configuration for advanced use cases
Code Comparison
UpUp:
upup.start({
'content-url': 'offline.html',
'assets': ['/img/logo.png', '/css/style.css']
});
next-pwa:
// next.config.js
const withPWA = require('next-pwa')({
dest: 'public'
})
module.exports = withPWA({
// your next.js config
})
Summary
UpUp is a lightweight solution for adding offline functionality to any web application, while next-pwa is specifically designed for Next.js projects with more comprehensive PWA features. UpUp offers simplicity and framework independence, but next-pwa provides deeper integration with Next.js and more advanced PWA capabilities. The choice between the two depends on the project's requirements and the development stack being used.
Webpack plugin that generates a service worker using sw-precache that will cache webpack's bundles' emitted assets. You can optionally pass sw-precache configuration options to webpack through this plugin.
Pros of sw-precache-webpack-plugin
- More mature and established project with a longer history
- Integrates seamlessly with webpack, making it easier to use in webpack-based projects
- Offers more granular control over service worker caching strategies
Cons of sw-precache-webpack-plugin
- No longer actively maintained, with the last update in 2018
- Lacks built-in support for modern PWA features like offline fallback pages
- May require more configuration and setup compared to next-pwa
Code Comparison
sw-precache-webpack-plugin:
new SWPrecacheWebpackPlugin({
cacheId: 'my-project-name',
filename: 'service-worker.js',
staticFileGlobs: ['dist/**/*.{js,html,css,png,jpg,gif,svg,eot,ttf,woff}'],
minify: true,
stripPrefix: 'dist/'
})
next-pwa:
const withPWA = require('next-pwa')({
dest: 'public'
})
module.exports = withPWA({
// your Next.js config
})
The code comparison shows that next-pwa requires less configuration and integrates more seamlessly with Next.js projects. sw-precache-webpack-plugin offers more detailed configuration options but requires more setup.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Zero Config PWA Plugin for Next.js
This plugin is powered by workbox and other good stuff.
ð Share your awesome PWA project ð here
Features
- 0ï¸â£ Zero config for registering and generating service worker
- ⨠Optimized precache and runtime cache
- ð¯ Maximize lighthouse score
- ð Easy to understand examples
- ð´ Completely offline support with fallbacks example ð
- ð¦ Use workbox and workbox-window v6
- ðª Work with cookies out of the box
- ð Default range requests for audios and videos
- â No custom server needed for Next.js 9+ example
- ð§ Handle PWA lifecycle events opt-in example
- ð Custom worker to run extra code with code splitting and typescript support example
- ð Public environment variables available in custom worker as usual
- ð Debug service worker with confidence in development mode without caching
- ð Internationalization (a.k.a I18N) with
next-i18next
example - ð Configurable by the same workbox configuration options for GenerateSW and InjectManifest
- ð Spin up a GitPod and try out examples in rocket speed
- â¡ Support blitz.js (simply add to
blitz.config.js
) - ð© (Experimental) precaching
.module.js
whennext.config.js
hasexperimental.modern
set totrue
NOTE 1 -
next-pwa
version 2.0.0+ should only work withnext.js
9.1+, and static files should only be served throughpublic
directory. This will make things simpler.NOTE 2 - If you encounter error
TypeError: Cannot read property **'javascript' of undefined**
during build, please consider upgrade to webpack5 innext.config.js
.
Install
If you are new to
next.js
orreact.js
at all, you may want to first checkout learn next.js or next.js document. Then start from a simple example or progressive-web-app example in next.js repository.
yarn add next-pwa
Basic Usage
Step 1: withPWA
Update or create next.config.js
with
const withPWA = require('next-pwa')({
dest: 'public'
})
module.exports = withPWA({
// next.js config
})
After running next build
, this will generate two files in your public
: workbox-*.js
and sw.js
, which will automatically be served statically.
If you are using Next.js version 9 or newer, then skip the options below and move on to Step 2.
If you are using Next.js older than version 9, you'll need to pick an option below before continuing to Step 2.
Option 1: Host Static Files
Copy files to your static file hosting server, so that they are accessible from the following paths: https://yourdomain.com/sw.js
and https://yourdomain.com/workbox-*.js
.
One example is using Firebase hosting service to host those files statically. You can automate the copy step using scripts in your deployment workflow.
For security reasons, you must host these files directly from your domain. If the content is delivered using a redirect, the browser will refuse to run the service worker.
Option 2: Use Custom Server
When an HTTP request is received, test if those files are requested, then return those static files.
Example server.js
const { createServer } = require('http')
const { join } = require('path')
const { parse } = require('url')
const next = require('next')
const app = next({ dev: process.env.NODE_ENV !== 'production' })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true)
const { pathname } = parsedUrl
if (pathname === '/sw.js' || /^\/(workbox|worker|fallback)-\w+\.js$/.test(pathname)) {
const filePath = join(__dirname, '.next', pathname)
app.serveStatic(req, res, filePath)
} else {
handle(req, res, parsedUrl)
}
}).listen(3000, () => {
console.log(`> Ready on http://localhost:${3000}`)
})
})
The following setup has nothing to do with
next-pwa
plugin, and you probably have already set them up. If not, go ahead and set them up.
Step 2: Add Manifest File (Example)
Create a manifest.json
file in your public
folder:
{
"name": "PWA App",
"short_name": "App",
"icons": [
{
"src": "/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/android-chrome-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#FFFFFF",
"background_color": "#FFFFFF",
"start_url": "/",
"display": "standalone",
"orientation": "portrait"
}
Step 3: Add Head Meta (Example)
Add the following into _document.jsx
or _app.tsx
, in <Head>
:
<meta name="application-name" content="PWA App" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="PWA App" />
<meta name="description" content="Best PWA App in the world" />
<meta name="format-detection" content="telephone=no" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="msapplication-config" content="/icons/browserconfig.xml" />
<meta name="msapplication-TileColor" content="#2B5797" />
<meta name="msapplication-tap-highlight" content="no" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/icons/touch-icon-iphone.png" />
<link rel="apple-touch-icon" sizes="152x152" href="/icons/touch-icon-ipad.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/icons/touch-icon-iphone-retina.png" />
<link rel="apple-touch-icon" sizes="167x167" href="/icons/touch-icon-ipad-retina.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="mask-icon" href="/icons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:url" content="https://yourdomain.com" />
<meta name="twitter:title" content="PWA App" />
<meta name="twitter:description" content="Best PWA App in the world" />
<meta name="twitter:image" content="https://yourdomain.com/icons/android-chrome-192x192.png" />
<meta name="twitter:creator" content="@DavidWShadow" />
<meta property="og:type" content="website" />
<meta property="og:title" content="PWA App" />
<meta property="og:description" content="Best PWA App in the world" />
<meta property="og:site_name" content="PWA App" />
<meta property="og:url" content="https://yourdomain.com" />
<meta property="og:image" content="https://yourdomain.com/icons/apple-touch-icon.png" />
<!-- apple splash screen images -->
<!--
<link rel='apple-touch-startup-image' href='/images/apple_splash_2048.png' sizes='2048x2732' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1668.png' sizes='1668x2224' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1536.png' sizes='1536x2048' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1125.png' sizes='1125x2436' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1242.png' sizes='1242x2208' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_750.png' sizes='750x1334' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_640.png' sizes='640x1136' />
-->
Tip: Put the
viewport
head meta tag into_app.js
rather than in_document.js
if you need it.
<meta
name='viewport'
content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover'
/>
Offline Fallbacks
Offline fallbacks are useful when the fetch failed from both cache and network, a precached resource is served instead of present an error from browser.
To get started simply add a /_offline
page such as pages/_offline.js
or pages/_offline.jsx
or pages/_offline.ts
or pages/_offline.tsx
. Then you are all set! When the user is offline, all pages which are not cached will fallback to '/_offline'.
Use this example to see it in action
next-pwa
helps you precache those resources on the first load, then inject a fallback handler to handlerDidError
plugin to all runtimeCaching
configs, so that precached resources are served when fetch failed.
You can also setup precacheFallback.fallbackURL
in your runtimeCaching config entry to implement similar functionality. The difference is that above method is based on the resource type, this method is based matched url pattern. If this config is set in the runtimeCaching config entry, resource type based fallback will be disabled automatically for this particular url pattern to avoid conflict.
Configuration
There are options you can use to customize the behavior of this plugin by adding pwa
object in the next config in next.config.js
:
const withPWA = require('next-pwa')({
dest: 'public'
// disable: process.env.NODE_ENV === 'development',
// register: true,
// scope: '/app',
// sw: 'service-worker.js',
//...
})
module.exports = withPWA({
// next.js config
})
Available Options
- disable: boolean - whether to disable pwa feature as a whole
- default:
false
- set
disable: false
, so that it will generate service worker in bothdev
andprod
- set
disable: true
to completely disable PWA - if you don't need to debug service worker in
dev
, you can setdisable: process.env.NODE_ENV === 'development'
- default:
- register: boolean - whether to let this plugin register service worker for you
- default to
true
- set to
false
when you want to handle register service worker yourself, this could be done incomponentDidMount
of your root app. you can consider the register.js as an example.
- default to
- scope: string - url scope for pwa
- default:
basePath
innext.config.js
or/
- set to
/app
so that path under/app
will be PWA while others are not
- default:
- sw: string - service worker script file name
- default:
/sw.js
- set to another file name if you want to customize the output file name
- default:
- runtimeCaching - caching strategies (array or callback function)
- default: see the Runtime Caching section for the default configuration
- accepts an array of cache entry objects, please follow the structure here
- Note: the order of the array matters. The first rule that matches is effective. Therefore, please ALWAYS put rules with larger scope behind the rules with a smaller and specific scope.
- publicExcludes - an array of glob pattern strings to exclude files in the
public
folder from being precached.- default:
['!noprecache/**/*']
- this means that the default behavior will precache all the files inside yourpublic
folder but files inside/public/noprecache
folder. You can simply put files inside that folder to not precache them without config this. - example:
['!img/super-large-image.jpg', '!fonts/not-used-fonts.otf']
- default:
- buildExcludes - an array of extra pattern or function to exclude files from being precached in
.next/static
(or your custom build) folder- default:
[]
- example:
[/chunks\/images\/.*$/]
- Don't precache files under.next/static/chunks/images
(Highly recommend this to work withnext-optimized-images
plugin) - doc: Array of (string, RegExp, or function()). One or more specifiers used to exclude assets from the precache manifest. This is interpreted following the same rules as Webpack's standard exclude option.
- default:
- cacheStartUrl - whether to cache start url
- default:
true
- discussion of use case to not cache start url at all
- default:
- dynamicStartUrl - if your start url returns different HTML document under different state (such as logged in vs. not logged in), this should be set to true.
- default:
true
- effective when
cacheStartUrl
set totrue
- recommend: set to false if your start url always returns same HTML document, then start url will be precached, this will help to speed up first load.
- default:
- dynamicStartUrlRedirect - if your start url redirect to another route such as
/login
, it's recommended to setup this redirected url for the best user experience.- default:
undefined
- effective when
dynamicStartUrlRedirect
set totrue
- default:
- fallbacks - config precached routes to fallback when both cache and network not available to serve resources.
- if you just need a offline fallback page, simply create a
/_offline
page such aspages/_offline.js
and you are all set, no configuration necessary - default:
object
fallbacks.document
- fallback route for document (page), default to/_offline
if you created that pagefallbacks.image
- fallback route for image, default to nonefallbacks.audio
- fallback route for audio, default to nonefallbacks.video
- fallback route for video, default to nonefallbacks.font
- fallback route for font, default to none
- if you just need a offline fallback page, simply create a
- cacheOnFrontEndNav - enable additional route cache when navigate between pages with
next/link
on front end. Checkout this example for some context about why this is implemented.- default:
false
- note: this improve user experience on special use cases but it also adds some overhead because additional network call, I suggest you consider this as a trade off.
- default:
subdomainPrefix: string - url prefix to allow hosting static files on a subdomaindefault:""
- i.e. default with no prefixexample:/subdomain
if the app is hosted onexample.com/subdomain
- deprecated, use basePath instead
- reloadOnOnline - changes the behaviour of the app when the device detects that it has gone back "online" and has a network connection. Indicate if the app should call
location.reload()
to refresh the app.- default:
true
- default:
- customWorkerDir - customize the directory where
next-pwa
looks for a custom worker implementation to add to the service worker generated by workbox. For more information, check out the custom worker example.- default:
worker
- default:
Other Options
next-pwa
uses workbox-webpack-plugin
, other options which could also be put in pwa
object can be found ON THE DOCUMENTATION for GenerateSW and InjectManifest. If you specify swSrc
, InjectManifest
plugin will be used, otherwise GenerateSW
will be used to generate service worker.
Runtime Caching
next-pwa
uses a default runtime cache.js
There is a great chance you may want to customize your own runtime caching rules. Please feel free to copy the default cache.js
file and customize the rules as you like. Don't forget to inject the configurations into your pwa
config in next.config.js
.
Here is the document on how to write runtime caching configurations, including background sync and broadcast update features and more!
Tips
- Common UX pattern to ask user to reload when new service worker is installed
- Use a convention like
{command: 'doSomething', message: ''}
object whenpostMessage
to service worker. So that on the listener, it could do multiple different tasks usingif...else...
. - When you are debugging service worker, constantly
clean application cache
to reduce some flaky errors. - If you are redirecting the user to another route, please note workbox by default only cache response with 200 HTTP status, if you really want to cache redirected page for the route, you can specify it in
runtimeCaching
such asoptions.cacheableResponse.statuses=[200,302]
. - When debugging issues, you may want to format your generated
sw.js
file to figure out what's really going on. - Force
next-pwa
to generate worker box production build by specify the optionmode: 'production'
in yourpwa
section ofnext.config.js
. Thoughnext-pwa
automatically generate the worker box development build during development (by runningnext
) and worker box production build during production (by runningnext build
andnext start
). You may still want to force it to production build even during development of your web app for following reason:- Reduce logging noise due to production build doesn't include logging.
- Improve performance a bit due to production build is optimized and minified.
- If you just want to disable worker box logging while keeping development build during development, simply put
self.__WB_DISABLE_DEV_LOGS = true
in yourworker/index.js
(create one if you don't have one). - It is common developers have to use
userAgent
string to determine if users are using Safari/iOS/MacOS or some other platform, ua-parser-js library is a good friend for that purpose.
Reference
- Google Workbox
- ServiceWorker, MessageChannel, & postMessage by Nicolás Bevacqua
- The Service Worker Lifecycle
- 6 Tips to make your iOS PWA feel like a native app
- Make Your PWA Available on Google Play Store
Fun PWA Projects
- Experience SAMSUNG on an iPhone - must open on an iPhone to start
- App Scope - like an app store for PWA
- PWA Directory
- PWA Builder - Alternative way to build awesome PWA
License
MIT
Top Related Projects
📦 Workbox: JavaScript libraries for Progressive Web Apps
make your Next.js application work offline using service workers via Google's workbox
❤️ JavaScript/TypeScript linter (ESLint wrapper) with great defaults
The React Framework
✈️ Easily create sites that work offline as well as online
Webpack plugin that generates a service worker using sw-precache that will cache webpack's bundles' emitted assets. You can optionally pass sw-precache configuration options to webpack through this plugin.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot