# Astro SW

[![Package information: NPM version](https://img.shields.io/npm/v/@ayco/astro-sw)](https://www.npmjs.com/package/@ayco/astro-sw)
[![Package information: NPM license](https://img.shields.io/npm/l/@ayco/astro-sw)](https://www.npmjs.com/package/@ayco/astro-sw)
[![Package information: NPM downloads](https://img.shields.io/npm/dt/@ayco/astro-sw)](https://www.npmjs.com/package/@ayco/astro-sw)

[![CI](https://github.com/ayo-run/astro-sw/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ayo-run/astro-sw/actions/workflows/ci.yml)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/ayo-run/astro-sw/badge)](https://scorecard.dev/viewer/?uri=github.com/ayo-run/astro-sw)

Use your own authored [service worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) with Astro.

The integration accepts the path to your service worker and automatically injects dynamic variables such as `__assets` generated by Astro for caching.

It works on both Astro output options — `static` and `server` — and lets developers retain the flexibility for various [caching strategies](https://developer.chrome.com/docs/workbox/caching-strategies-overview/).

## Get in touch

1. Submit tickets via [SourceHut todo](https://todo.sr.ht/~ayoayco/astro-sw)
1. Start a [GitHub discussion](https://github.com/ayo-run/astro-sw/discussions)
1. Email me: [hi@ayo.run](mailto:hi@ayo.run)

## Installation

In your [Astro](https://astro.build) project:

```bash
# if using npm
$ npm i @ayco/astro-sw

# if using pnpm
$ pnpm add @ayco/astro-sw
```

## Minimal Usage

Here's an example `astro.config.mjs` file:

```js
import { defineConfig } from 'astro/config'
import serviceWorker from '@ayco/astro-sw'

export default defineConfig({
  integrations: [
    serviceWorker({
      path: './src/sw.ts',
    }),
  ],
})
```

For more options available, see the [API](#api).

## TypeScript support

We use `esbuild` to resolve service worker `imports` and build TS files! You can customize the build options by providing it to the `esbuild` configuration property.

```js
import { defineConfig } from 'astro/config'
import serviceWorker from '@ayco/astro-sw'

export default defineConfig({
  integrations: [
    serviceWorker({
      path: './src/sw.ts',
      esbuild: {
        minify: true,
      },
    }),
  ],
})
```

## Injected variables

The most important variable your service worker will have access to is `__assets`, which contains all routes and public assets that Astro includes in your build. Additionally, you will also get `__prefix` and `__version` you can use for naming & invalidating your Cache storage (useful for debugging purposes).

## `eslint` globals

Because of the injected variables not being defined in your script, you might get `eslint` errors for the undefined variables when you have the `no-undef` rule. To prevent this, you can use our exported `globals` object in your eslint config as follows:

```js
import astroSwGlobals from '@ayco/astro-sw/globals'

export default [
  {
    languageOptions: {
      globals: {
        ...astroSwGlobals,
      },
    },
  },
  // add more generic rule sets here, such as:
  // jsPlugin.configs.recommended,
]
```

## Registration Hooks

Hooks are provided for adding custom logic that triggers in various service worker registration events.

The following properties are available for the `registrationHooks` configuration:

1. `installing` - when the registration is 'installing'
1. `waiting` - when the registration is 'waiting'
1. `active` - when the registration is 'active'
1. `error` - when the registration throws an error
1. `unsupported` - when the service workers are unsupported
1. `afterRegistration` - after the registration succeeds

```js
import { defineConfig } from 'astro/config'
import serviceWorker from '@ayco/astro-sw'

export default defineConfig({
  integrations: [
    serviceWorker({
      path: './src/sw.ts',
      registrationHooks: {
        afterRegistration: async () => {
          const sw = await navigator.serviceWorker.getRegistration()
          console.log('>>> registrered', sw)
        },
        installing: () => console.log('installing...'),
        waiting: () => console.log('waiting...'),
        active: () => console.log('active...'),
        error: (error) => console.error(error),
        unsupported: () => console.log(':('),
      },
    }),
  ],
})
```

## API

The integration accepts a configuration object with the following properties

| property            | type                                           | required? | notes                                                                                                                                                                                                     |
| ------------------- | ---------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| path                | string                                         | required  | path to your _own_ service worker script; no surprises & easy debugging                                                                                                                                   |
| assetCachePrefix    | string                                         | optional  | cache storage name prefix                                                                                                                                                                                 |
| assetCacheVersionID | string                                         | optional  | cache storage name versioning; by default, a random UUID is used                                                                                                                                          |
| include             | string[]                                       | optional  | list of URL of resources not in the public directory or generated by Astro, but you want to be cached. Beware that non-existent routes that result to HTTP Error404 will cause the service worker to fail |
| exclude             | string[]                                       | optional  | list of URL or routes you want to be ignored/removed from cached assets                                                                                                                                   |
| logAssets           | boolean                                        | optional  | set to see a list of the assets found; defaults to false                                                                                                                                                  |
| esbuild             | [BuildOptions](https://esbuild.github.io/api/) | optional  | custom build options for your service worker script                                                                                                                                                       |
| registrationHooks   | object                                         | optional  | provide callbacks for various registration events; see section on [Registration Hooks](#registration-hooks)                                                                                               |

---

_Just keep building._<br>
_A project by [Ayo](https://ayo.ayco.io)_
