@jon49/sw 0.14.7 → 0.14.8

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.
@@ -4,84 +4,83 @@ import path from "node:path"
4
4
  import { getHash, glob, write } from "./system.ts"
5
5
 
6
6
  export interface FileMapper {
7
- url: string
8
- file: string
7
+ url: string
8
+ file: string
9
9
  }
10
10
 
11
11
  function isFileMapper(x: any | undefined): x is FileMapper {
12
- return x?.url && x?.file
12
+ return x?.url && x?.file
13
13
  }
14
14
 
15
15
  let option: { isRunning: boolean, isWaiting: NodeJS.Timeout | null } = {
16
- isRunning: false,
17
- isWaiting: null
16
+ isRunning: false,
17
+ isWaiting: null
18
18
  }
19
19
 
20
20
  export async function fileMapper(targetDirectory: string, force = false) {
21
- if (option.isRunning || option.isWaiting || !force) {
22
- if (option.isWaiting) {
23
- clearTimeout(option.isWaiting)
24
- }
25
- option.isWaiting = setTimeout(() => {
26
- option.isWaiting = null
27
- fileMapper(targetDirectory, true)
28
- }, 30)
29
- return
30
- }
31
- try {
32
- option.isRunning = true
33
- console.time("File Mapper")
34
-
35
- let oldFileMapperFiles = await glob("**/file-map.*.js", targetDirectory)
36
- Promise.all(oldFileMapperFiles.map(async x => {
37
- await rm(`${targetDirectory}/${x}`)
38
- }))
39
-
40
- let files: string[] = await glob("**/*.{js,css,json,ico,svg,png}", targetDirectory)
41
-
42
- let mapper = files.map(x => {
43
- let parsed = path.parse(x)
44
- let parsed2 = path.parse(parsed.name)
45
- let url = `/${parsed.dir}/${parsed2.name}${parsed.ext}`
46
- let file = `/${x}`
47
- return {
48
- url,
49
- file,
50
- }
51
- })
52
- .filter(isFileMapper)
53
-
54
- if (option.isWaiting) return
55
- // Write mapper to file in src/web/file-map.js
56
- let fileMapJsonContent = JSON.stringify(mapper)
57
- let hash = getHash(fileMapJsonContent)
58
- let fileMapUrl = `/web/file-map.${hash}.js`
59
-
60
- fileMapJsonContent = `${fileMapJsonContent.slice(0, -1)},{"url":"/web/file-map.js","file":"${fileMapUrl}"}]`
61
-
62
- let fileMapContent = `(() => { self.app = { links: ${fileMapJsonContent} } })()`
63
- await write(`${targetDirectory}${fileMapUrl}`, fileMapContent)
64
-
65
- let globalFiles =
66
- mapper
67
- .filter(x => x.url.includes(".global."))
68
- .map(x => x.file)
69
- .join(`","`)
70
-
71
- let swFile = mapper.find(x => x.url === "/web/sw.js")?.file
72
-
73
- let globals = `${globalFiles && `"`}${globalFiles}${globalFiles && `",`}`
74
- // Create service worker central file
75
- if (option.isWaiting) return
76
- await write(
77
- `${targetDirectory}/web/sw.js`,
78
- `importScripts("${fileMapUrl}",${globals}"${swFile}")`)
79
-
80
- } catch (error) {
81
- console.error(error)
82
- } finally {
83
- option.isRunning = false
84
- console.timeEnd("File Mapper")
21
+ if (option.isRunning || option.isWaiting || !force) {
22
+ if (option.isWaiting) {
23
+ clearTimeout(option.isWaiting)
85
24
  }
25
+ option.isWaiting = setTimeout(() => {
26
+ option.isWaiting = null
27
+ fileMapper(targetDirectory, true)
28
+ }, 30)
29
+ return
30
+ }
31
+ try {
32
+ option.isRunning = true
33
+ console.time("File Mapper")
34
+
35
+ let oldFileMapperFiles = await glob("**/file-map.*.js", targetDirectory)
36
+ Promise.all(oldFileMapperFiles.map(async x => {
37
+ await rm(`${targetDirectory}/${x}`)
38
+ }))
39
+
40
+ let files: string[] = await glob("**/*.{js,css,json,ico,svg,png}", targetDirectory)
41
+
42
+ let mapper = files.map(x => {
43
+ let parsed = path.parse(x)
44
+ let parsed2 = path.parse(parsed.name)
45
+ let url = `/${parsed.dir}/${parsed2.name}${parsed.ext}`
46
+ let file = `/${x}`
47
+ return {
48
+ url,
49
+ file,
50
+ }
51
+ })
52
+ .filter(isFileMapper)
53
+
54
+ if (option.isWaiting) return
55
+ // Write mapper to file in src/web/file-map.js
56
+ let fileMapJsonContent = JSON.stringify(mapper)
57
+ let hash = getHash(fileMapJsonContent)
58
+ let fileMapUrl = `/web/file-map.${hash}.js`
59
+
60
+ fileMapJsonContent = `${fileMapJsonContent.slice(0, -1)},{"url":"/web/file-map.js","file":"${fileMapUrl}"}]`
61
+
62
+ let fileMapContent = `(() => { self.app = { links: ${fileMapJsonContent} } })()`
63
+ await write(`${targetDirectory}${fileMapUrl}`, fileMapContent)
64
+
65
+ let globalFiles =
66
+ mapper
67
+ .filter(x => x.url.includes(".global."))
68
+ .map(x => x.file)
69
+ .join(`","`)
70
+
71
+ let swFile = mapper.find(x => x.url === "/web/sw.js")?.file
72
+
73
+ let globals = `${globalFiles && `"`}${globalFiles}${globalFiles && `",`}`
74
+ // Create service worker central file
75
+ if (option.isWaiting) return
76
+ await write(
77
+ `${targetDirectory}/web/sw.js`,
78
+ `importScripts("${fileMapUrl}",${globals}"${swFile}")`)
79
+
80
+ } catch (error) {
81
+ console.error(error)
82
+ } finally {
83
+ option.isRunning = false
84
+ console.timeEnd("File Mapper")
85
+ }
86
86
  }
87
-
@@ -1,4 +1,5 @@
1
1
  // https://deanhume.com/displaying-a-new-version-available-progressive-web-app/
2
+ const isDev = ["localhost", "127.0.0.1"].includes(document.location.hostname)
2
3
  let refreshing = false
3
4
  // The event listener that is fired when the service worker updates
4
5
  // Here we reload the page
@@ -12,15 +13,13 @@ navigator.serviceWorker.addEventListener('controllerchange', function () {
12
13
  /// @param fn - Callback function to be called when a new version is available
13
14
  /// @returns void
14
15
  /// @example
15
- /// notifier((state, worker) => {
16
- /// if (state !== "waiting") {
17
- /// // Show notification
18
- /// }
16
+ /// notifier((worker) => {
17
+ /// // Show notification to user about new version
19
18
  /// if (/* user confirms update */) {
20
19
  /// worker.postMessage("skipWaiting")
21
20
  /// }
22
21
  /// })
23
- function notifier(fn: (state: "" | "waiting", worker: ServiceWorker) => void) {
22
+ function notifier(fn: (worker: ServiceWorker) => void) {
24
23
  let newWorker: ServiceWorker | undefined | null
25
24
 
26
25
  if ('serviceWorker' in navigator) {
@@ -28,7 +27,7 @@ function notifier(fn: (state: "" | "waiting", worker: ServiceWorker) => void) {
28
27
  navigator.serviceWorker.register('/web/sw.js').then(reg => {
29
28
  if ((newWorker = reg.waiting)?.state === 'installed') {
30
29
  // @ts-ignore
31
- fn("waiting", newWorker)
30
+ fn(newWorker)
32
31
  return
33
32
  }
34
33
  reg.addEventListener('updatefound', () => {
@@ -37,11 +36,19 @@ function notifier(fn: (state: "" | "waiting", worker: ServiceWorker) => void) {
37
36
 
38
37
  newWorker?.addEventListener('statechange', () => {
39
38
 
40
- // There is a new service worker available, show the notification
41
- if (newWorker?.state === "installed" && navigator.serviceWorker.controller) {
42
- navigator.serviceWorker.controller.postMessage("installed")
43
- fn("", newWorker)
44
- }
39
+ // There is a new service worker available, show the notification
40
+ if (newWorker?.state === "installed" && navigator.serviceWorker.controller) {
41
+ navigator.serviceWorker.controller.postMessage("installed")
42
+ // If we're in dev/server auto-activate the new worker
43
+ if (isDev) {
44
+ try {
45
+ newWorker.postMessage({ action: 'skipWaiting' })
46
+ } catch (err) {
47
+ // Ignore if worker doesn't accept messages
48
+ }
49
+ }
50
+ fn(newWorker)
51
+ }
45
52
 
46
53
  })
47
54
  })
@@ -60,7 +67,7 @@ function skipWaiting(id: string) {
60
67
  })
61
68
  }
62
69
 
63
- function notifyUserAboutNewVersion(state = "", worker: ServiceWorker) {
70
+ function notifyUserAboutNewVersion(worker: ServiceWorker) {
64
71
  let nav = document.getElementById("sw-message")
65
72
  nav?.insertAdjacentHTML("afterbegin", `<div class=inline><a id=skipWaiting href="#">Click here to update your app.</a></div>`)
66
73
  // @ts-ignore
@@ -69,11 +76,4 @@ function notifyUserAboutNewVersion(state = "", worker: ServiceWorker) {
69
76
  window.app = window.app || {}
70
77
  // @ts-ignore
71
78
  window.app.sw = worker
72
- if (state === "waiting") return
73
- // Publish custom event for "user-messages" to display a toast.
74
- document.dispatchEvent(new CustomEvent("user-messages", {
75
- detail: { html: `A new version of the app is available. <a id=skipWaiting1 href="#">Click to update the app.</a>` }
76
- }))
77
- // @ts-ignore
78
- skipWaiting("skipWaiting1")
79
79
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jon49/sw",
3
- "version": "0.14.7",
3
+ "version": "0.14.8",
4
4
  "description": "Packages for MVC service workers.",
5
5
  "type": "module",
6
6
  "files": [