Skip to content

Commit

Permalink
chore(docs): reworded some pages
Browse files Browse the repository at this point in the history
  • Loading branch information
DuCanhGH committed May 5, 2024
1 parent 0e6e741 commit 6334bb6
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 144 deletions.
2 changes: 1 addition & 1 deletion docs/content/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Introduction
type: Docs
---

# Welcome to DuCanh's PWA suite for Next.js!
# Welcome to `@ducanh2912/next-pwa`

Take a look around:

Expand Down
14 changes: 5 additions & 9 deletions docs/content/next-pwa/configuring.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,7 @@ export default withPWA({

## Other options

`next-pwa` uses `workbox-webpack-plugin` under the hood, other options can be found in the documentation 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).

To pass these options to `workbox-webpack-plugin`, change your `next.config.js` like so:
`next-pwa` uses `workbox-webpack-plugin` under the hood. As such, its options are also available:

<Tabs>

Expand Down Expand Up @@ -136,9 +133,8 @@ export default withPWA({

## Runtime caching

`next-pwa` has a default list of caching strategies, see: [cache.ts](https://github.com/DuCanhGH/next-pwa/tree/master/packages/next-pwa/src/cache.ts)

If you want to have your own runtime caching rules, change your `next.config.js` like so:
`next-pwa` provides [a list of caching strategies out of the box](https://github.com/DuCanhGH/next-pwa/tree/master/packages/next-pwa/src/cache.ts).
You can also write your own list like so:

<Tabs>

Expand Down Expand Up @@ -181,6 +177,6 @@ export default withPWA({
</Tabs>

<Callout>
Also check out [the documentation on how to write a runtime caching
array](https://developer.chrome.com/docs/workbox/reference/workbox-build/#type-RuntimeCaching)!
Also check out [Workbox's documentation on
`runtimeCaching`](https://developer.chrome.com/docs/workbox/reference/workbox-build/#type-RuntimeCaching).
</Callout>
18 changes: 9 additions & 9 deletions docs/content/next-pwa/custom-worker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ type: Docs

# Custom worker

`next-pwa` will automatically detect `worker/index.{js,ts}`, and bundle the file into `dest` as `worker-*.js` using `webpack`.
It's also automatically injected into the generated `sw.js`. In this way, you get the benefit of code splitting automatically.
You can share logic between your web app and this worker (path aliases do work). You can even import npm packages there!
`next-pwa` allows you to inject some custom code into the generated service worker. By default, this code should be located at `worker/index.{js,ts}`.
The plugin will check if the file exists and bundle the file to `dest/worker-*.js` if it does.

This is where you can write your custom worker logic.

For example, to disable Workbox's logging, you can simply add `self.__WB_DISABLE_DEV_LOGS = true` to it.
<Callout variant="warning">
Do not use this feature to write critical worker code that your application depends on to function. Again, the service worker should function as an
enhancement, not something critical to your application.
</Callout>

You can change the directory in which `next-pwa` looks for a custom worker implementation, change its output directory, or
change its file structure:
You can change the directory in which `next-pwa` looks for a custom worker implementation and change the directory in which `next-pwa` outputs the bundled
worker:

<Tabs>

Expand Down Expand Up @@ -50,7 +50,7 @@ export default withPWA({

</Tabs>

In this example, `next-pwa` will look for `service-worker/index.{js,ts}`, bundles it if it is available, then emits the result
In this example, `next-pwa` will look for `service-worker/index.{js,ts}`, bundle it if it is available, and then emit the result
to `somewhere-else/not/a-worker-*.js`.

<Callout variant="warning">
Expand Down
96 changes: 4 additions & 92 deletions docs/content/next-pwa/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pnpm add @ducanh2912/next-pwa && pnpm add -D webpack

</Tabs>

## Basic usage
## Implementation

### Step 1: Wrap your Next config with `withPWA`

Expand Down Expand Up @@ -134,74 +134,9 @@ export default nextConfigFunction;
After running `next build`, this will generate two files in your `public` directory: `workbox-*.js` and `sw.js`, which will
automatically be served statically.

### Step 1.5: Next.js < 9
### Step 2: Add a web application manifest

If you are using Next.js >= 9, then skip the section below.

Otherwise, you'll need to pick one of the two options below before continuing.

#### Option 1: Hosting 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`.

An example is using Firebase hosting service to host those files statically. You can automate the copying step with scripts
in your deployment workflow.

<Callout variant="warning">
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.
</Callout>

#### Option 2: Using a custom server

Example server:

```js
// title server.js
const { createServer } = require("http");
const { join } = require("path");
const { parse } = require("url");
const next = require("next");

const dev = process.env.NODE_ENV !== "production";
const hostname = "localhost";
const port = 3000;

const app = next({ dev, hostname, port });
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(port, () => {
console.log(`> Ready on http://${hostname}:${port}`);
});
});
```

<Callout>
It is recommended to upgrade your Next.js version instead. Usually, Next.js
will provide codemods needed to migrate between major versions (see [Next.js
codemods](https://nextjs.org/docs/advanced-features/codemods)). Its releases
are often packed with a lot of awesome features, and you shouldn't miss out on
them.
</Callout>

### Step 2: Add a manifest.json file

Create a `manifest.json` file in your `public` folder:
Update `app/manifest.json` (App Router) or `public/manifest.json` (Pages Router) with the following content:

```json
// title public/manifest.json
Expand Down Expand Up @@ -234,7 +169,7 @@ Create a `manifest.json` file in your `public` folder:
}
```

### Step 3: Add `<meta />` and `<link />` tags to your `<head />`
### Step 3: Add metadata to `<head />`

Add the following to your `app/layout.tsx` or `pages/_app.tsx`:

Expand Down Expand Up @@ -379,26 +314,3 @@ export default function App({ Component, pageProps }: AppProps) {

</Tabs>

## Tips

- [You may want to ask user to reload when a new service worker is installed](https://github.com/DuCanhGH/next-pwa/tree/master/examples/lifecycle/components/PWALifecycle.tsx#L20-L40)

- When you are debugging the service worker, remember to constantly clean the application cache to reduce some flaky errors.

- If you are redirecting the user to another route, please note that [Workbox by default only caches responses 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` by setting `options.cacheableResponse.statuses` to `[200, 302]`.

- When debugging issues, sometimes you may want to format your generated `sw.js` file to figure out what's really going on. In development mode it is not minified
though, so it is readable to an extent.

- You can force `next-pwa` to generate the SW in production mode by setting `workboxOptions.mode` to `"production"`.
By default, `next-pwa` generates the SW in development mode for `next dev` and in production mode for `next build` and `next start`,
but you may still want to force it to build in production mode even during development because of one of these reasons:

- Reduced logging noise as the production build doesn't include logging.
- Improved performance as the production build is better optimized.

However, if you just want to disable Workbox's logging, simply add `self.__WB_DISABLE_DEV_LOGS = true` to your [`worker/index.ts`](/docs/next-pwa/custom-worker).

- If you want to get your user's `userAgent` string, use [ua-parser-js](https://www.npmjs.com/package/ua-parser-js)!
31 changes: 19 additions & 12 deletions docs/content/next-pwa/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,32 @@ type: Docs

Welcome to the `next-pwa` documentation!

## What is `next-pwa`?
## What is `@ducanh2912/next-pwa`?

`next-pwa` is a plugin for Next.js that allows you to create a progressive web app with it.
`@ducanh2912/next-pwa` is a package that allows you to create a progressive web app with Next.js.

With it, building a PWA is simply painless, just drop `withPWA` into your `next.config.js` and you are already good to go!
This is the predecessor of `@serwist/next`. If you are just getting started, we recommend using [Serwist](https://serwist.pages.dev) instead.

It is also really configurable as it uses Workbox under the hood to build the service worker.
## How to install `@ducanh2912/next-pwa`?

## How to install `next-pwa`?

See [Getting started](/docs/next-pwa/getting-started). It should have abundant information on how to set the plugin up, including additional information for
older versions of Next.js and tips!
See [Getting started](/docs/next-pwa/getting-started).

## How to configure it?

See [Configuring](/docs/next-pwa/configuring). All available options are listed there!
See [Configuring](/docs/next-pwa/configuring).

## Does it support offline mode?

Yes! Offline mode is supported out of the box. Assets such as `.js` files, `.css` files, images are automatically cached as they are requested (some are even
precached!). Pages are also cached as you visits them. If you are offline before they are cached, you won't be disappointed still [should you have offline
fallbacks enabled](/docs/next-pwa/offline-fallbacks).
Out of the box, JavaScript, CSS, and images assets are precached, and pages are cached as you visits them. You can also enable [offline
fallbacks](/docs/next-pwa/offline-fallbacks) to handle uncached assets and pages.

For more information, see [Offline support](/docs/next-pwa/offline-fallbacks).

## Alternatives

There are also some alternatives to `@ducanh2912/next-pwa`:

- [`@serwist/next`](https://serwist.pages.dev/docs/next)
- [`@serwist/webpack-plugin`](https://serwist.pages.dev/docs/webpack-plugin)
- [`workbox-webpack-plugin`](https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin)
- [`next-pwa`](https://github.com/shadowwalker/next-pwa)
4 changes: 0 additions & 4 deletions docs/content/next-pwa/offline-fallbacks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,3 @@ export default withPWA({

`next-pwa` helps you precache those resources on first load, then inject a fallback handler to `handlerDidError` plugin to all
`runtimeCaching` entries, so that precached resources are served when fetching fails.

You can also setup `precacheFallback.fallbackURL` in your [runtimeCaching array](https://developer.chrome.com/docs/workbox/reference/workbox-build/#type-RuntimeCaching)
to implement a similar functionality. The difference is that the above method is based on the resource type, whereas this method is based on matched URL pattern. If this config
is set in any `runtimeCaching` entry, the aforementioned resource-based method will be disabled for that particular entry to avoid conflicts.
12 changes: 11 additions & 1 deletion docs/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,20 @@
body {
@apply m-0 flex h-full w-full p-0;
}
html {
@apply scroll-smooth;
}
body {
@apply box-border bg-neutral-50 transition-colors duration-100 dark:bg-neutral-950;
}

details > summary {
@apply cursor-pointer select-none list-none;
}
details > summary::-webkit-details-marker {
@apply hidden;
}

#__next,
#root-container {
@apply m-0 flex h-fit min-h-screen w-full flex-col p-0;
Expand Down Expand Up @@ -50,7 +60,7 @@

@media (prefers-reduced-motion) {
html {
@apply !animate-none !transition-none;
@apply !animate-none !scroll-auto !transition-none;
}
html *,
html *:before,
Expand Down
22 changes: 6 additions & 16 deletions docs/src/shared/TocContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,25 @@
import { Heading, type HeadingProps } from "@/components/Heading";
import { clsx } from "@/utils/clsx";
import Link from "next/link";
import { type ReactNode, createContext, useEffect, useState, type DetailedHTMLProps, type AnchorHTMLAttributes, use, useRef } from "react";
import { type ReactNode, createContext, useEffect, useState, type DetailedHTMLProps, type AnchorHTMLAttributes, use, useRef, act } from "react";

interface TocContextProperties {
activeId: string | null;
activeId: Set<string>;
observer: IntersectionObserver | null;
}

export const TocContext = createContext<TocContextProperties>({ activeId: null, observer: null });
export const TocContext = createContext<TocContextProperties>({ activeId: null!, observer: null });

export const TocProvider = ({ children }: { children: ReactNode }) => {
const [activeId, setActiveId] = useState<TocContextProperties["activeId"]>(null);
const [activeId, setActiveId] = useState<TocContextProperties["activeId"]>(new Set<string>());
const [observer, setObserver] = useState<TocContextProperties["observer"]>(null);

useEffect(() => {
if (!observer) {
setObserver(
new IntersectionObserver(
(entries) => {
let found = false;
for (const entry of entries) {
if (entry.isIntersecting) {
setActiveId(entry.target.id);
found = true;
break;
}
}
if (!found) {
setActiveId(null);
}
setActiveId(() => new Set(entries.filter((e) => e.isIntersecting).map((e) => `#${e.target.id}`)));
},
{
rootMargin: "0% 0% 0% 0%",
Expand Down Expand Up @@ -72,7 +62,7 @@ export const TocLink = ({ href, className, ...rest }: TocLinkProps) => {
if (href?.startsWith("#")) {
const { activeId } = use(TocContext);

return <a href={href} className={clsx("text-toc", href.slice(1) === activeId && "active", className)} {...rest} />;
return <a href={href} className={clsx("text-toc", activeId.has(href) && "active", className)} {...rest} />;
}

// Same origin
Expand Down

0 comments on commit 6334bb6

Please sign in to comment.