Skip to content

Commit

Permalink
feat: support for appDir
Browse files Browse the repository at this point in the history
  • Loading branch information
DuCanhGH committed Nov 30, 2022
1 parent a8dbaab commit d0cb3fb
Show file tree
Hide file tree
Showing 18 changed files with 266 additions and 154 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@
### Fix

1. (the real) Fix for not precache server js
2. Fix service worker register url edge case
2. Fix Service Worker register url edge case

## 5.4.7

### Fix

1. (the real) Fix for not precache server js
2. Fix service worker register url edge case
2. Fix Service Worker register url edge case

## 5.4.6

Expand Down Expand Up @@ -368,7 +368,7 @@

### Fix

- Remove POST api runtime cache from default cache configuration as it's not supported in service worker
- Remove POST api runtime cache from default cache configuration as it's not supported in Service Worker

## 3.1.0

Expand Down
91 changes: 19 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,27 @@ This plugin is powered by [Workbox](https://developer.chrome.com/docs/workbox/)

**Features**

- 0️⃣ Zero config for registering and generating service worker
- 0️⃣ Zero config for registering and generating Service Worker
- ✨ Optimized precache and runtime cache
- 💯 Maximize lighthouse score
- 💯 Maximize Lighthouse score
- 🎈 Easy to understand examples
- 📴 Completely offline support with fallbacks [example](https://github.com/DuCanhGH/next-pwa/tree/master/examples/offline-fallback-v2) 🆕
- 📦 Use [workbox](https://developer.chrome.com/docs/workbox/) and [workbox-window](https://developer.chrome.com/docs/workbox/modules/workbox-window) v6
- 📦 Use [Workbox](https://developer.chrome.com/docs/workbox/) and [workbox-window](https://developer.chrome.com/docs/workbox/modules/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](https://github.com/DuCanhGH/next-pwa/tree/master/examples/next-9)
- 🔧 Handle PWA lifecycle events opt-in [example](https://github.com/DuCanhGH/next-pwa/tree/master/examples/lifecycle)
- 📐 Custom worker to run extra code with code splitting and **typescript** support [example](https://github.com/DuCanhGH/next-pwa/tree/master/examples/custom-ts-worker)
- 📐 Custom worker to run extra code with code splitting and **Typescript** support [example](https://github.com/DuCanhGH/next-pwa/tree/master/examples/custom-ts-worker)
- 📜 [Public environment variables](https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser) available in custom worker as usual
- 🐞 Debug service worker with confidence in development mode without caching
- 🐞 Debug Service Worker with confidence in development mode without caching
- 🌏 Internationalization (a.k.a I18N) with `next-i18next` [example](https://github.com/DuCanhGH/next-pwa/tree/master/examples/next-i18next)
- 🛠 Configurable by the same [workbox configuration options](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin) for [GenerateSW](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin/#generatesw-plugin) and [InjectManifest](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin/#injectmanifest-plugin)
- 🚀 Spin up a [GitPod](https://gitpod.io/#https://github.com/DuCanhGH/next-pwa/) and try out examples in rocket speed
- ⚡ Support [blitz.js](https://blitzjs.com/) (simply add to `blitz.config.js`)

> **NOTE 1** - `next-pwa` version 2.0.0+ should only work with `Next.js` 9.1+, and static files should only be served through `public` 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 Webpack 5 in `next.config.js`](https://github.com/shadowwalker/next-pwa/issues/198#issuecomment-817205700).
> **NOTE 2** - If you encounter error `TypeError: Cannot read property **'javascript' of undefined**` during build, [please consider upgrading to Webpack 5 in `next.config.js`](https://github.com/shadowwalker/next-pwa/issues/198#issuecomment-817205700).
---

Expand Down Expand Up @@ -85,7 +85,7 @@ Copy files to your static file hosting server, so that they are accessible from

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.
> 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

Expand Down Expand Up @@ -304,85 +304,32 @@ export default withPWA({

### 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 both `dev` and `prod`
- set `disable: true` to completely disable PWA
- if you don't need to debug service worker in `dev`, you can set `disable: process.env.NODE_ENV === 'development'`
- 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 in `componentDidMount` of your root app. you can consider the [register.js](https://github.com/DuCanhGH/next-pwa/blob/master/register.js) as an example.
- scope: string - url scope for pwa
- default: [`basePath`](https://nextjs.org/docs/api-reference/next.config.js/basepath) in `next.config.js` or `/`
- set to `/app` so that path under `/app` will be PWA while others are not
- sw: string - service worker script file name
- default: `/sw.js`
- set to another file name if you want to customize the output file name
- 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](https://developer.chrome.com/docs/workbox/reference/workbox-build/#type-RuntimeCaching)
- 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 your `public` 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']`
- 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 with `next-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.
- cacheStartUrl - whether to cache start url
- default: `true`
- [discussion of use case to not cache start url at all](https://github.com/shadowwalker/next-pwa/pull/296#issuecomment-1094167025)
- 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 to `true`
- 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.
- 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 to `true`
- 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 as `pages/_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 page
- `fallbacks.image` - fallback route for image, default to none
- `fallbacks.audio` - fallback route for audio, default to none
- `fallbacks.video` - fallback route for video, default to none
- `fallbacks.font` - fallback route for font, default to none
- cacheOnFrontEndNav - enable additional route cache when navigate between pages with `next/link` on front end. Checkout this [example](https://github.com/DuCanhGH/next-pwa/tree/master/examples/cache-on-front-end-nav) 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.
- ~~subdomainPrefix: string - url prefix to allow hosting static files on a subdomain~~
- ~~default: `""` - i.e. default with no prefix~~
- ~~example: `/subdomain` if the app is hosted on `example.com/subdomain`~~
- deprecated, use [basePath](https://nextjs.org/docs/api-reference/next.config.js/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`
- 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/DuCanhGH/next-pwa/tree/master/examples/custom-ts-worker).
- default: `worker`
See [PluginOptions](https://github.com/DuCanhGH/next-pwa/blob/master/src/types.ts?plain=1#L3)

### Other Options

`next-pwa` uses `workbox-webpack-plugin`, other options which could also be put in `pwa` object can be found [**ON THE DOCUMENTATION**](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin) for [GenerateSW](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin/#generatesw-plugin) and [InjectManifest](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin/#injectmanifest-plugin). If you specify `swSrc`, `InjectManifest` plugin will be used, otherwise `GenerateSW` will be used to generate service worker.
`next-pwa` uses `workbox-webpack-plugin`, other options can be found in [Google's documentation for workbox-webpack-plugin](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin) for [GenerateSW](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin/#generatesw-plugin) and [InjectManifest](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin/#injectmanifest-plugin).

### Runtime Caching

`next-pwa` uses a default runtime [cache.js](https://github.com/DuCanhGH/next-pwa/blob/master/cache.js)
`next-pwa` specifies a default runtime caching [cache.js](https://github.com/DuCanhGH/next-pwa/blob/master/src/cache.ts)

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`.
There is a chance you may want to have your own runtime caching rules. Please feel free to copy the default `cache.ts` file and customize the rules as you like. Don't forget to inject the configurations into your `withPWAInit`'s config in `next.config.js`.

Here is the [document on how to write runtime caching configurations](https://developer.chrome.com/docs/workbox/reference/workbox-build/#type-RuntimeCaching), including background sync and broadcast update features and more!
Here is the [document on how to write a runtime caching configuration](https://developer.chrome.com/docs/workbox/reference/workbox-build/#type-RuntimeCaching), including background sync and broadcast update and more!

## Tips

1. [Common UX pattern to ask user to reload when new service worker is installed](https://github.com/DuCanhGH/next-pwa/blob/master/examples/lifecycle/pages/index.js#L26-L38)
2. Use a convention like `{command: 'doSomething', message: ''}` object when `postMessage` to service worker. So that on the listener, it could do multiple different tasks using `if...else...`.
3. When you are debugging service worker, constantly `clean application cache` to reduce some flaky errors.
1. [Common UX pattern to ask user to reload when new Service Worker is installed](https://github.com/DuCanhGH/next-pwa/blob/master/examples/lifecycle/pages/index.js#L26-L38)
2. Use a convention like `{command: 'doSomething', message: ''}` object when `postMessage` to Service Worker. So that on the listener, it could do multiple different tasks using `if...else...`.
3. When you are debugging Service Worker, constantly `clean application cache` to reduce some flaky errors.
4. If you are redirecting the user to another route, please note [workbox by default only cache response with 200 HTTP status](https://developer.chrome.com/docs/workbox/modules/workbox-cacheable-response#what_are_the_defaults), if you really want to cache redirected page for the route, you can specify it in `runtimeCaching` such as `options.cacheableResponse.statuses=[200,302]`.
5. When debugging issues, you may want to format your generated `sw.js` file to figure out what's really going on.
6. Force `next-pwa` to generate worker box production build by specify the option `mode: 'production'` in your `pwa` section of `next.config.js`. Though `next-pwa` automatically generate the worker box development build during development (by running `next`) and worker box production build during production (by running `next build` and `next start`). You may still want to force it to production build even during development of your web app for following reason:
1. Reduce logging noise due to production build doesn't include logging.
2. Improve performance a bit due to production build is optimized and minified.
6. Force `next-pwa` to generate worker box production build by specify the option `mode: 'production'` in your `withPWAInit`'s config in `next.config.js`. Though `next-pwa` automatically generate the worker box development build during development (by running `next`) and worker box production build during production (by running `next build` and `next start`). You may still want to force it to build for production even in development mode of your web app for following reason:
1. Reduce logging noise as the production build doesn't include logging.
2. Improve performance a bit as the production build is better optimized.
7. If you just want to disable worker box logging while keeping development build during development, [simply put `self.__WB_DISABLE_DEV_LOGS = true` in your `worker/index.js` (create one if you don't have one)](https://github.com/DuCanhGH/next-pwa/blob/c48ef110360d0138ad2dacd82ab96964e3da2daf/examples/custom-worker/worker/index.js#L6).
8. 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](https://www.npmjs.com/package/ua-parser-js) library is a good friend for that purpose.
8. It is common for developers to have to use `userAgent` string to determine if users are using Safari/iOS/MacOS or some other platform, [ua-parser-js](https://www.npmjs.com/package/ua-parser-js) library is a good friend for that purpose.

## Reference

Expand Down
4 changes: 2 additions & 2 deletions examples/cache-on-front-end-nav/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ This example demonstrates how to use `next-pwa` plugin to solve the issue when u

For context, `next.js` embraces both SSR and front end routing (typical SPA) to deliver smooth users experience. However, when a user navigate on the web app through `next/router` or `next/link` (Link component), the navigation is made through front end routing. Which means there is no HTTP GET request made to the server for that route, it only swap the react component to the new page and change the url showed on the url bar. This "fake" navigation is usually desired because it means users do not have to wait for network delay.

However the problem appears when it comes to caching, because there is not request that service worker could intercept, nothing is cached. Users may landing on your home page and navigate to different pages without doing any caching. When the network is lost and users reload these pages using refresh button or re-open the browser, a network lost page from the browser is present, bummer! This behavior could leave users very confused as they could navigated the web app without problem in online and offline, when it come back offline, the web app stopped working.
However the problem appears when it comes to caching, because there is not request that Service Worker could intercept, nothing is cached. Users may landing on your home page and navigate to different pages without doing any caching. When the network is lost and users reload these pages using refresh button or re-open the browser, a network lost page from the browser is present, bummer! This behavior could leave users very confused as they could navigated the web app without problem in online and offline, when it come back offline, the web app stopped working.

So we have to enforce a cache for each front-end caching. Yes, it adds additional network traffic which seems conflict of what we are trying to achieve with front end routing. But since the cache happens in service worker, it should have trivial impact on user experience or more specifically, page load.
So we have to enforce a cache for each front-end caching. Yes, it adds additional network traffic which seems conflict of what we are trying to achieve with front end routing. But since the cache happens in Service Worker, it should have trivial impact on user experience or more specifically, page load.

I personally feel it's a trade off for you to decide whether you want to improve this user experience.

Expand Down
8 changes: 4 additions & 4 deletions examples/custom-ts-worker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

[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.
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.ts` 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.
Simply create a `worker/index.ts` 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!
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!

> - In dev mode, `worker/index.ts` is not watched, so it will not hot reload.
Expand Down Expand Up @@ -44,7 +44,7 @@ module.exports = withPWA({
});
```

Then service worker generated will automatically import your code and run it before other workbox code.
Then Service Worker generated will automatically import your code and run it before other workbox code.

## Usage

Expand Down
Loading

0 comments on commit d0cb3fb

Please sign in to comment.