ts-service-worker 1.0.31 → 1.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +89 -96
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,23 +1,21 @@
1
+ ## Goals
1
2
 
2
-
3
- ## Why
4
-
5
- Service workers are a powerful tool for developers to improve the user experience, providing for fine-grained caching, offline usage and progressive web apps (PWAs). It replaced the coarse-grained _AppCache_, which proved quite hard to effectively use.
6
-
7
- Unfortunately, the service worker API is so low-level it can be hard to use. It requires series of nested promise chains, and quickly grows complicated. In the documentation there are good examples describing single specific strategies. While these are readable, they are minimally useful because real-world usage requires integrating several of these strategies at the same time. This can be error-prone and hard to follow. And as anyone who has developed service workers knows, they are tedious to test because of their more complex lifecycle.
8
-
9
- And since service workers run in the browser, they must be written in the browser's version Javascript. If this likely involves transpilation, which will requiring additional complexity in the build process to produce a separate artifact.
10
-
11
- There are a [other libraries](#other-libraries) designed to help, which may be useful to you. **TS-Service-worker** aims to solve specific challenges. It:
12
-
13
- - is written in Typescript and fully typed
14
- - avoids nesting and promise chains
15
- - has a declarative API to _describe_ your webapp caching
3
+ - provide declarative support for the most common caching strategies
16
4
  - supports easy integration of multiple caching strategies
17
- - build a compatible service-worker.js that requires no additional transpilation
5
+ - produces a `service-worker.js` that requires no additional transpilation
6
+ - avoids nesting and promise chains
7
+ - is written in Typescript and fully typed
18
8
  - can scan your disk for resources to cache
19
9
  - provides built-in debug logging
20
- - provides simple a simple cache clearing rule
10
+ - provides clear and simple cache purging rules
11
+
12
+ Copyright (c) 2023 Andrew J. Peterson, dba NDP Software
13
+
14
+ #### NOTICE
15
+ This is in testing... It works on two very different projects. I'd love people to try it out and provide feedback.
16
+
17
+ ## Overview
18
+ The idea is simple. You provide TS-Service-Worker with a **Plan** (and options), and it outputs a functional Javascript file that can be sent to the browser. The **Plan** is a series of caching strategies to be applied, along with the paths they should be applied to.
21
19
 
22
20
  ## Examples
23
21
 
@@ -26,22 +24,22 @@ The very simplest service worker might provide an offline backup of the whole si
26
24
  import {requestHandler, Origin} from "ts-service-worker";
27
25
 
28
26
  export const plan: Plan = [
29
- {paths: Origin, strategy: "networkFirst"}
27
+ {paths: Origin, strategy: "networkFirst"} // don't do this!
30
28
  ]
31
29
  app.get('/service-worker.js', requestHandler(plan))
32
30
  ```
33
- This plan says, "intercept all the requests from the origin and below (usually everything under `/`), and serve if from the network if available, otherwise, serve from the cache." This is just one of the example caching strategies, and demonstrates:
31
+ This plan says, "intercept all the requests from the root of the site and below (everything under `/`), and serve them from the network if available; otherwise, serve from the cache." This is just one of the example caching strategies, and demonstrates:
34
32
 
35
- - declarative configuration
33
+ - declarative configuration
36
34
  - conveniences like `Origin` that make doing simple things simple
37
- - how a simple caching strategy is insufficent.
35
+ - how a simple caching strategy is insufficent. (shrug)
38
36
 
39
37
  Some of the deficiences of this strategy:
40
38
  - it only caches paths that have been visited
41
39
  - provides no way to update cached files
42
40
  - caches everything fetched, even unimportant resources
43
41
 
44
- A real caching plan requires more nuance. Here's a slightly more realistic plan:
42
+ A real caching plan requires more nuance. Here is part of a slightly more realistic plan:
45
43
  ```ts
46
44
  export const plan: Plan =
47
45
  [
@@ -50,10 +48,10 @@ export const plan: Plan =
50
48
  {strategy: 'staticOfflineBackup', [/.*\.html/], backup: '/networkDown.html'}
51
49
  ]
52
50
  ```
53
- Here, we see multiple strategies in action. Each request is evaluated (sequentially) against the paths, and the first matching strategy is applied.
51
+ Here, we see multiple strategies in action. Each request is evaluated (sequentially) against the paths, and the first matching strategy is applied. (If not strategy matches, the resource is fetched as normal.)
54
52
  - The path `open-search.xml` will never be cached,
55
53
  - `/my-data.json` will be served from the cache and re-fetched in the background, available for a later access.
56
- - Finally, the file `/networkDown.html` will be cached, and served as a replacement for other HTML pages when the network is down.
54
+ - Finally, the file `/networkDown.html` will be cached, and served as a replacement for other HTML pages when their fetching fails.
57
55
 
58
56
  Another common strategy is to pre-cache some resources on disk. These can be explicitly listed, or dynamically determined from glob matches of files on disk:
59
57
  ```ts
@@ -62,19 +60,16 @@ Another common strategy is to pre-cache some resources on disk. These can be exp
62
60
  files: { glob: '*.png', dir: 'src/assets/images', prefix: '/img'}
63
61
  }
64
62
  ```
65
- These are just some examples. Each app is different and requires careful consideration and crafting. **TS-service-worker** makes developing a custom caching service worker easy and error-free.
63
+ These are just some examples. Each app is different and requires careful consideration and crafting. **TS-Service-Worker** makes developing a custom caching service worker easy and error-free.
66
64
 
67
65
  ## Usage
68
66
 
69
- There are a few ways to use this:
67
+ After npm installing, there are a few ways to use this:
70
68
 
71
- ### CLI
69
+ ### Within Express
72
70
 
73
- 1. Create a `service-worker.ts` file that exports a `plan` variable
74
- 2. Run `> ts-sw service-worker.ts`
75
- 3. Serve the resultant file as your service worker, editing the Typescript file and regenerating as needed.
71
+ Using directly within Express (or equivalent) will be the most convenient and provides the best Typescript type hints:
76
72
 
77
- ### Within Express
78
73
  ```ts
79
74
  import { requestHandler } from 'ts-service-worker'
80
75
  app.get('/service-worker.js', requestHandler([
@@ -82,84 +77,65 @@ app.get('/service-worker.js', requestHandler([
82
77
  ]))
83
78
  })
84
79
  ```
80
+
81
+ ### CLI
82
+
83
+ The CLI will generate the Javascript file from the specifications in a JSON file. This is nice because it's declarative, but lacks the typing of a Typescript solution.
84
+
85
+ 1. Create a `sw-plan.json` file with `plan` and `options`. See below for available properties.
86
+ 2. Run `> npx ts-service-worker sw-plan.json >dist/service-worker.js`
87
+ 3. Serve the resultant file (`dist/service-worker.js`) as your service worker, and reference it in your HTML head.
88
+ 4. Editing the JSON file and regenerate as needed.
89
+
85
90
  ### Other
86
91
  There are other ways to incorporate this into your build cycle. The library exposes a method `generateServiceWorker` which accepts a plan and options and generates the necessary Javascript (text). Let me know how you do it!
87
92
 
88
- Note that the output of this tool needs no post-processing, so it's best to avoid these tools for the service worker if possible. If the code output isn't compatible, let me know and I'll fix it right away.
93
+ Note that the output of this tool needs _no_ post-processing, so it's best to avoid these tools for the service worker if possible. If the code output isn't compatible, let me know and I'll fix it right away.
89
94
 
90
- ## Options
95
+ ### Options
91
96
 
92
- The following may be provided as options, and they effect the generation of the Javascript code:
97
+ The following may be provided as options for any usage method, and they effect the generation of the Javascript code:
93
98
 
94
- * version – semantic version of the worker. Major version bump means to reset the cache.
95
- * skipWaiting – executes the normal skip waiting logic, and allows your service worker to come into play without all the browser windows being closed.
96
- * debug – outputs log messages as files are fetched. This is too noise for production, but may be useful to figure out what is going on with your service worker.
99
+ * `version` – semantic version of the worker. Major version bump means to reset the cache.
100
+ * `skipWaiting` – executes the normal skip waiting logic, and allows your service worker to come into play without all the browser windows being closed.
101
+ * `debug` – outputs log messages as files are fetched. This is too noise for production, but may be useful to figure out what is going on with your service worker.
97
102
 
98
103
  ## Paths
99
104
 
100
- Paths can be:
105
+ Paths expressions will match URLs requested from your website, and must be included in each strategy of a plan. The path property can be:
101
106
  - a string URL path. This is intepreted as the meaning the URL must END with this pattern
102
107
  - a RegExp, matching the full URL
103
- - an array of strings or RegExp
108
+ - an array of strings or RegExp, following the rules above
104
109
  - the symbol `Symbol.for('origin')`, which matches everything under the service worker's domain.
105
110
  - the symbol `Symbol.for('scope')`, which matches everything under the service worker's scope, which is the level that a service worker is installed at.
106
111
 
107
112
  ## Strategies
108
113
 
109
- **ts-service-worker**
110
-
111
- ### cache-on-install
112
-
113
- Tell it paths to cache when the service worker activates.
114
-
115
- Also, it can scan directories from resources. This is optional, but for some use cases you will have a whole directory of files you want to pre-cache. Use normal glob patterns to identify these as shown below.
116
- ```ts
117
- plan: Plan = [
118
- {
119
- files: {
120
- glob: '**/*.png',
121
- dir: 'src/images',
122
- prefix: '/assets'
123
- },
124
- strategy: 'cache on install'
125
- }
126
- ]
127
- ```
128
- The globs are evaluated with the `service-worker.js` file is created, so updating resources will require rebuilding the file.
129
-
130
114
  ### cacheFirst
131
115
 
132
- Ideal for: CSS, images, fonts, JS, templates… basically anything you'd consider static to that "version" of your site.
116
+ This strategy is ideal for CSS, images, fonts, JS, templates… basically anything you'd consider static to that "version" of your site. Per [https://web.dev/learn/pwa/serving/#cache-first]:
133
117
  >> Using this strategy, the service worker looks for the matching request in the cache and returns the corresponding Response if it's cached. Otherwise it retrieves the response from the network (~~optionally,~~ updating the cache for future calls). If there is neither a cache response nor a network response, the request will error. Since serving assets without going to the network tends to be faster, this strategy prioritizes performance over freshness.
134
118
 
135
119
  There is no way to remove files from the cache. For this reason, use only for immutable resources (certain images and fingerprinted assets). If these do need to be updated, you will need to [rebuild the cache (see below)](#Rebuild Cache).
136
120
 
137
- See [https://web.dev/learn/pwa/serving/#cache-first].
138
-
139
-
140
121
  ### networkFirst
141
-
142
- This is most useful to provide the user with a backup in case the network isn't available.
122
+ This is most useful to provide the user with a backup in case the network isn't available. Per [https://web.dev/learn/pwa/serving/#network-first]:
143
123
 
144
124
  > This strategy is the mirror of the Cache First strategy; it checks if the request can be fulfilled from the network and, if it can't, tries to retrieve it from the cache. If there is neither a network response nor a cache response, the request will error. Getting the response from the network is usually slower than getting it from the cache, this strategy prioritizes updated content instead of performance.
145
125
 
146
- See [https://web.dev/learn/pwa/serving/#network-first].
147
-
148
126
  ### staleWhileRevalidate
149
127
 
150
- This is useful for resources that could be slow to fetch but where freshness is not critical.
128
+ This is useful for resources that could be slow to fetch and whose freshness is not critical. Per [https://web.dev/learn/pwa/serving/#stale-while-revalidate]:
151
129
 
152
130
  > The stale while revalidate strategy returns a cached response immediately, then checks the network for an update, replacing the cached response if one is found. This strategy always makes a network request, because even if a cached resource is found, it will try to update what was in the cache with what was received from the network, to use the updated version in the next request. This strategy, therefore, provides a way for you to benefit from the quick serving of the cache first strategy and update the cache in the background.
153
131
 
154
132
  > With this strategy, the assets are updated in the background. This means your users won't get the new version of the assets until the next time that path is requested. At that time the strategy will again check if a new version exists and the cycle repeats.
155
133
 
156
- See https://web.dev/learn/pwa/serving/#stale-while-revalidate
157
-
158
134
  ### networkOnly
159
135
 
136
+ Per [https://web.dev/learn/pwa/serving/#network-only]:
137
+
160
138
  > The network only strategy is similar to how browsers behave without a service worker or the Cache Storage API. Requests will only return a resource if it can be fetched from the network. This is often useful for resources like online-only API requests.
161
- >
162
- See https://web.dev/learn/pwa/serving/#network-only
163
139
 
164
140
  ### staticOfflineBackup
165
141
 
@@ -169,53 +145,70 @@ The backup resource is loaded on service worker installation and served as neede
169
145
 
170
146
  Note: this currently doesn't support inline SVGs that you see in some examples, but requires using a separate file.
171
147
 
172
- Note: this does **not** serve the "backup" file from cache by default. If you want to do that, use another strategy in combination. This likely is `networkFirst`, but it's up to you.
148
+ Note: this does **not** serve the "backup" file from cache by default. If you want to do that, use another strategy like `networkFirst` in combination.
173
149
 
150
+ ### cache-on-install
174
151
 
175
- ## Rebuild Cache
152
+ Cache specific paths when the service worker installs. Because it needs to know specific resources, path matching wildcards and regular expression will not work. But this strategy has an extra feature that other strategies do not: it can scan directories for resources. In some cases this, when you have a whole directory of files to pre-cache, this will be the least maintenance. Use normal glob patterns to identify these as shown below. Here's one example:
176
153
 
177
- The browsers will manage the cache, removing items if it becomes too larger.
154
+ ```ts
155
+ plan: Plan = [
156
+ {
157
+ files: {
158
+ glob: '**/*.png',
159
+ dir: 'src/images', // where to start searching
160
+ prefix: '/assets' // prefix applied to any matches
161
+ },
162
+ strategy: 'cache on install'
163
+ }
164
+ ]
165
+ ```
166
+ The globs are evaluated when the `service-worker.js` file is created, so updating resources will require rebuilding the service worker file.
167
+
168
+ ## Cache and Versioning of Service Workers
169
+
170
+ When developing service workers, it can take a while to learn service worker behavior, understanding when it re-installs service workers and rebuilds caches. This is worth understanding, but **TS-Service-Worker** tries the appropriate controls.
171
+
172
+ #### Clearing the Cache
173
+ There are two components that relevant here:
178
174
 
179
- Most of the strategies will replace older assets with newer ones when found.
175
+ - the service worker
176
+ - the cache (of responses)
180
177
 
181
- If you _need_ to reset the cache, simply increment the version number. A major version bump means the whole cache is replaced. See [#versioning] below.
178
+ When building your service worker, provide a `version` string in the options, follow semvar conventions. If you change this at all, the service worker will be re-installed (because it has changed). This, in itself, will _not_ affect the cached files. But, if the _major version_ changes, the cache (of responses) will be deleting and a new one created. _With this library, the way to reset the cache in users' browsers is to bump the major version number._ (To test locally, you can use the browser's developer tools.)
182
179
 
183
- ## Versioning
180
+ That being said, you're not in complete control. Browsers will manage the actual response cache, removing items if it becomes too large. These limits are quite high in modern browsers. Some of the strategies implemented here will replace older assets with newer ones when found; some won't. This should be documented above or obvious.
184
181
 
185
- Service workers themselves have no concept of versioning. The browser manages downloading the service worker on page load, and if it's "out of date", it will notice. It will install the new service worker and then wait until the current one isn't in use, and replace it with the new one. This generally means a new service worker won't come into play until the user closes the windows, so it may be some time. To accelerate this, pass `skipWaiting` in the options, which will activate the service worker as soon as it is downloaded.
182
+ #### Skip Waiting
186
183
 
187
- Service workers themselves don't have the concept of semantic versioning, but this library provides a simple one: you can provide a VERSION string. The first component of it (the major version number), will be used to name the cache. If this changes, the cache is deleting and a new one created. This is the only effective way of resetting the cache from the service worker. (To test locally, you will use the browser's developer tools.)
184
+ Service workers themselves will re-install when they have changed-- based on the browsers' rules. This wil be confusing at first, though, as new service workers will not normally be installed. The default behavior for service workers is to wait until all the windows associated with the service worker are closed, and then install the new service worker. If this isn't what you want, you can accellerate this by passing `skipWaiting: true` in the options. This will install the service worker as soon as it is download-- but still will not be available as the page loads, but usually it will be ready on the next reload.
188
185
 
186
+ ## Why TS-Service-Worker?
189
187
 
188
+ Service workers are a powerful tool for developers to improve the user experience, providing for fine-grained caching, offline usage and progressive web apps (PWAs). It replaced the coarse-grained _AppCache_, which proved quite hard to effectively use and was retired.
190
189
 
191
- Strategies:
192
- precache
193
- cache
194
- prefetching (on installation)
195
- offline responses
196
- network-first
197
- cache-first
198
- offline backup
190
+ Unfortunately, the service worker API is also hard to use, as it is quite low-level. It requires a series of nested promise chains, and quickly grows complicated. In the documentation there are good examples describing single specific strategies. While these are readable, they are minimally useful because real-world usage requires integrating several of these strategies at the same time. This can be error-prone and hard to follow. And as anyone who has developed service workers knows, they are tedious to test because of the complex lifecycle.
191
+
192
+ And since service workers run in the browser, they must be written in the browser's version Javascript. This likely involves transpilation, which will requiring additional complexity in the build process to produce a separate artifact. It can be quite challenging in a Typescript project.
193
+
194
+ There are a [other libraries](#other-libraries) designed to help, which may be useful to you. **TS-Service-Worker** aims to solve specific challenges.
199
195
 
200
196
  ## TODO
201
- 1. Fix backup to ONLY serve backup if network fails.
202
- 2. Command line
203
- https://web.dev/learn/pwa/serving/#cache-only
197
+ 2. https://web.dev/learn/pwa/serving/#cache-only
204
198
  3. filter/only to process only certain types, eg. only: /https?:.*/
205
199
  4. allowOnly: /
206
200
  5. https://web.dev/learn/pwa/workbox/#offline-fallback
207
201
  https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#recovering_failed_requests ALSO offline SVG: https://github.com/veiss-com/sw-tools#offline
208
202
  6. https://github.com/veiss-com/sw-tools#limiting-the-cache-size
209
203
  7. expiring cache
210
- 8. change name of service worker request handler. requesthandler?
211
204
 
212
- REFERENCE
213
- https://web.dev/learn/pwa/serving/
214
- https://web.dev/offline-cookbook/#on-network-response
205
+ ## References
206
+ These are the basics of how service workers function:
207
+ - https://web.dev/learn/pwa/serving/
208
+ - https://web.dev/offline-cookbook/#on-network-response
215
209
 
216
210
  Interesting reference showing the complexities: https://adactio.com/serviceworker.js and https://adactio.medium.com/cache-limiting-in-service-workers-d6741361ca19
217
211
 
218
-
219
212
  ## Other Libraries
220
213
  - https://web.dev/learn/pwa/workbox/ -- popular and very cool tool. This will work for many projects, but I was looking for something where I had a little more control.
221
214
  - https://vite-pwa-org.netlify.app/frameworks/sveltekit.html
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-service-worker",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "Generate caching service-worker.js using declarative Typescript.",
5
5
  "author": {
6
6
  "name": "Andrew Peterson, NDP Software",