diff --git a/README.md b/README.md index 5fa5c72c..309fdf55 100644 --- a/README.md +++ b/README.md @@ -291,6 +291,8 @@ module.exports = withPWA({ - default: `true` - 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](https://github.com/shadowwalker/next-pwa/tree/master/examples/custom-ts-worker). - default: `worker` +- customWorkerWebpack - Function to customize the webpack configuration for bundling custom workers. Receives the configuration object with default settings and must return the modified one. + - default: `undefined` ### Other Options diff --git a/build-custom-worker.js b/build-custom-worker.js index 8d90ff6e..ad56c056 100644 --- a/build-custom-worker.js +++ b/build-custom-worker.js @@ -6,7 +6,7 @@ const webpack = require('webpack') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const TerserPlugin = require('terser-webpack-plugin') -const buildCustomWorker = ({ id, basedir, customWorkerDir, destdir, plugins, minify }) => { +const buildCustomWorker = ({ id, basedir, customWorkerDir, destdir, plugins, minify, webpack: customWebpack }) => { let workerDir = undefined if (fs.existsSync(path.join(basedir, customWorkerDir))) { @@ -36,7 +36,7 @@ const buildCustomWorker = ({ id, basedir, customWorkerDir, destdir, plugins, min const customWorkerEntry = customWorkerEntries[0] console.log(`> [PWA] Custom worker found: ${customWorkerEntry}`) console.log(`> [PWA] Build custom worker: ${path.join(destdir, name)}`) - webpack({ + const baseConfig = { mode: 'none', target: 'webworker', entry: { @@ -106,7 +106,15 @@ const buildCustomWorker = ({ id, basedir, customWorkerDir, destdir, plugins, min minimizer: [new TerserPlugin()] } : undefined - }).run((error, status) => { + }; + + let config = baseConfig; + if (typeof customWebpack === 'function') { + console.log('> [PWA] Using provided webpack config to build custom worker') + config = customWebpack(baseConfig); + } + + webpack(config).run((error, status) => { if (error || status.hasErrors()) { console.error(`> [PWA] Failed to build custom worker`) console.error(status.toString({ colors: true })) diff --git a/examples/custom-worker-webpack/.eslintrc.json b/examples/custom-worker-webpack/.eslintrc.json new file mode 100644 index 00000000..bffb357a --- /dev/null +++ b/examples/custom-worker-webpack/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/examples/custom-worker-webpack/README.md b/examples/custom-worker-webpack/README.md new file mode 100644 index 00000000..d52dea2e --- /dev/null +++ b/examples/custom-worker-webpack/README.md @@ -0,0 +1,68 @@ +# next-pwa - custom worker example + +[TOC] + +This example demonstrates how to use `next-pwa` plugin to turn a `next.js` based web application into a progressive web application easily. It demonstrates how to add custom worker code to the service worker generated by workbox. + +## New Method + +Simply create a `worker/index.js` and start implementing your service worker. `next-pwa` will detect this file automatically, and bundle the file into `dest` as `worker-*.js` using `webpack`. It's also automatically injected into `sw.js` generated. + +In this way, you get benefit of code splitting and size minimization automatically. Yes! `require` modules works! Yes! you can share codes between web app and the service worker! + +> - Typescript support for `worker/index.ts` current not supported. +> +> - In dev mode, `worker/index.js` is not watch, so it will not hot reload. + +### Custom Worker Directory + +You can customize the directory of your custom worker file by setting the `customWorkerDir` relative to the `basedir` in the `pwa` section of your `next.config.js`: + +```javascript +const withPWA = require('next-pwa')({ + customWorkerDir: 'serviceworker' + ... +}) + +module.exports = withPWA({ + // next.js config +}) +``` + +In this example, `next-pwa` would look for `serviceworker/index.js`. + +## Old Method (Still Works) + +Basically you need to create a file such as `worker.js` in `public` folder, then add an option `importScripts` to `pwa` object in `next.config.js`: + +```javascript +const withPWA = require('next-pwa')({ + dest: 'public', + importScripts: ['/worker.js'] +}) + +module.exports = withPWA({ + // next.js config +}) +``` + +Then service worker generated will automatically import your code and run it before other workbox code. + +## Usage + +[](https://gitpod.io/#https://github.com/shadowwalker/next-pwa/) + +```bash +cd examples/custom-server +yarn install +yarn build +yarn start +``` + +## Recommend `.gitignore` + +``` +**/public/workbox-*.js +**/public/sw.js +**/public/worker-*.js +``` diff --git a/examples/custom-worker-webpack/next.config.js b/examples/custom-worker-webpack/next.config.js new file mode 100644 index 00000000..d005bd07 --- /dev/null +++ b/examples/custom-worker-webpack/next.config.js @@ -0,0 +1,17 @@ +const withPWA = require('next-pwa')({ + dest: 'public', + customWorkerWebpack(config) { + return { + ...config, + resolve: { + ...config.resolve, + alias: { + ...config.resolve.alias, + '@util': path.resolve(__dirname, './src'), + } + } + }; + } +}) + +module.exports = withPWA() diff --git a/examples/custom-worker-webpack/package.json b/examples/custom-worker-webpack/package.json new file mode 100644 index 00000000..bc9d6d14 --- /dev/null +++ b/examples/custom-worker-webpack/package.json @@ -0,0 +1,23 @@ +{ + "name": "next-pwa-example", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "private": true, + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "babel-loader": "^8.2.5", + "next": "^12.2.5", + "next-pwa": "latest", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "eslint": "^8.22.0", + "eslint-config-next": "12.2.5" + } +} diff --git a/examples/custom-worker-webpack/pages/_document.js b/examples/custom-worker-webpack/pages/_document.js new file mode 100644 index 00000000..5b3d1c9f --- /dev/null +++ b/examples/custom-worker-webpack/pages/_document.js @@ -0,0 +1,50 @@ +import Document, { Html, Head, Main, NextScript } from 'next/document' + +const APP_NAME = 'next-pwa example' +const APP_DESCRIPTION = 'This is an example of using next-pwa plugin' + +class _Document extends Document { + static async getInitialProps(ctx) { + return await Document.getInitialProps(ctx) + } + + render() { + return ( + +
+ + + + + + + + + {/* TIP: set viewport head meta tag in _app.js, otherwise it will show a warning */} + {/* */} + + + + + + + + +