Security News
ESLint is Now Language-Agnostic: Linting JSON, Markdown, and Beyond
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
next-pwa is a plugin for Next.js that helps you turn your Next.js application into a Progressive Web App (PWA) with minimal configuration. It provides features like offline support, caching strategies, and service worker integration.
Offline Support
This configuration enables offline support by generating a service worker that caches your assets and pages, allowing your app to work offline.
const withPWA = require('next-pwa');
module.exports = withPWA({
pwa: {
dest: 'public'
}
});
Custom Caching Strategies
This configuration allows you to define custom caching strategies for different types of assets. In this example, images are cached using a 'CacheFirst' strategy.
const withPWA = require('next-pwa');
module.exports = withPWA({
pwa: {
dest: 'public',
runtimeCaching: [
{
urlPattern: /\.(?:png|jpg|jpeg|svg|gif)$/,
handler: 'CacheFirst',
options: {
cacheName: 'images',
expiration: {
maxEntries: 50,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
},
},
},
],
},
});
Service Worker Customization
This configuration allows you to customize the service worker behavior, such as enabling it only in production, skipping the waiting phase, and automatically registering it.
const withPWA = require('next-pwa');
module.exports = withPWA({
pwa: {
dest: 'public',
register: true,
skipWaiting: true,
disable: process.env.NODE_ENV === 'development',
},
});
workbox-webpack-plugin is a plugin for webpack that generates a service worker and precaches assets. It offers more granular control over caching strategies and service worker behavior compared to next-pwa, but requires more configuration.
next-offline is another Next.js plugin that helps you create a PWA. It provides similar functionalities to next-pwa, such as offline support and service worker integration, but it is less actively maintained.
sw-precache-webpack-plugin is a webpack plugin that generates a service worker using sw-precache. It is similar to workbox-webpack-plugin but is less feature-rich and is generally considered outdated in favor of Workbox.
This plugin is powered by workbox and other good stuff.
Features
yarn add next-pwa
Update or create next.config.js
with
const withPWA = require('next-pwa')
module.exports = withPWA({
// other next config
})
After running next build
, this will generate two files in your distDir
(default is .next
folder): precache-manifest.*.js
and sw.js
, which you need to serve statically, either through static file hosting service or using custom server.js
.
If you are using Next.js 9+, you may not need a custom server to host your service worker files. Skip to next section to see the details.
Copy files to your static file hosting server, so that they could be access using URL: https://yourdomain.com/sw.js
and https://yourdomain.com/precache-manifest.*.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.
When a 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' || pathname.startsWith('/precache-manifest.')) {
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 to set them up.
Create a manifest.json
file in your static
folder:
{
"name": "PWA App",
"short_name": "App",
"icons": [
{
"src": "/static/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/static/icons/android-chrome-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/static/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#FFFFFF",
"background_color": "#FFFFFF",
"start_url": "/",
"display": "standalone",
"orientation": "portrait"
}
Add following into _document.jsx
or _document.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='/static/icons/browserconfig.xml' />
<meta name='msapplication-TileColor' content='#2B5797' />
<meta name='msapplication-tap-highlight' content='no' />
<meta name='theme-color' content='#000000' />
<meta name='viewport' content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover' />
<link rel='apple-touch-icon' sizes='180x180' href='/static/icons/apple-touch-icon.png' />
<link rel='icon' type='image/png' sizes='32x32' href='/static/icons/favicon-32x32.png' />
<link rel='icon' type='image/png' sizes='16x16' href='/static/icons/favicon-16x16.png' />
<link rel='manifest' href='/static/manifest.json' />
<link rel='mask-icon' href='/static/icons/safari-pinned-tab.svg' color='#5bbad5' />
<link rel='shortcut icon' href='/static/icons/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/static/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/static/icons/apple-touch-icon.png' />
There are options you can use to customize behavior of this plugin by adding pwa
object in the next config in next.config.js
:
const withPWA = require('next-pwa')
module.exports = withPWA({
pwa: {
disable: false,
register: true,
scope: '/app',
sw: 'service-worker.js',
//...
}
})
Thanks to Next.js 9+, we can use public
folder (currently an experimental feature) to serve static files from root url path. It cuts the need to write custom server only to serve those files. Therefore the setup is more easy and concise. We can use next.config.js
to config next-pwa
to generates service worker and precache files into public
folder.
const withPWA = require('next-pwa')
module.exports = withPWA({
pwa: {
dest: 'public'
},
experimental: {
publicDirectory: true
}
})
Use this example to see it in action
dev
disable: false
, so that it will generate service worker in both dev
and prod
disable: true
to completely disable PWAtrue
false
when you want to handle register service worker yourself, this could be done in componentDidMount
of your root app. you can consider the register.js as an example./
/app
, so that all sub url under /app
will be PWA, other url paths are still normal web app with no PWA support./sw.js
next-pwa
uses workbox-webpack-plugin
, other options which could also be put in pwa
object can be find ON THE DOCUMENTATION. If you specify swSrc
, InjectManifest
plugin will be used, otherwise GenerateSW
will be used to generate service worker.
const defaultCache = [{
urlPattern: /^https:\/\/fonts\.(?:googleapis|gstatic)\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts',
expiration: {
maxEntries: 4,
maxAgeSeconds: 365 * 24 * 60 * 60 // 365 days
}
}
}, {
urlPattern: /^https:\/\/use\.fontawesome\.com\/releases\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'font-awesome',
expiration: {
maxEntries: 1,
maxAgeSeconds: 365 * 24 * 60 * 60 // 365 days
}
}
}, {
urlPattern: /\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,
handler: 'StaleWhileRevalidate',
options: {
cacheName: 'static-font-assets',
expiration: {
maxEntries: 4,
maxAgeSeconds: 7 * 24 * 60 * 60 // 7 days
}
}
}, {
urlPattern: /\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,
handler: 'StaleWhileRevalidate',
options: {
cacheName: 'static-image-assets',
expiration: {
maxEntries: 64,
maxAgeSeconds: 24 * 60 * 60 // 24 hours
}
}
}, {
urlPattern: /\.(?:js)$/i,
handler: 'StaleWhileRevalidate',
options: {
cacheName: 'static-js-assets',
expiration: {
maxEntries: 16,
maxAgeSeconds: 24 * 60 * 60 // 24 hours
}
}
}, {
urlPattern: /\.(?:css|less)$/i,
handler: 'StaleWhileRevalidate',
options: {
cacheName: 'static-style-assets',
expiration: {
maxEntries: 16,
maxAgeSeconds: 24 * 60 * 60 // 24 hours
}
}
}, {
urlPattern: /.*/i,
handler: 'StaleWhileRevalidate',
options: {
cacheName: 'others',
expiration: {
maxEntries: 16,
maxAgeSeconds: 24 * 60 * 60 // 24 hours
}
}
}]
MIT
FAQs
Next.js with PWA, powered by workbox.
The npm package next-pwa receives a total of 138,423 weekly downloads. As such, next-pwa popularity was classified as popular.
We found that next-pwa demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Security News
Members Hub is conducting large-scale campaigns to artificially boost Discord server metrics, undermining community trust and platform integrity.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.