@docusaurus/plugin-pwa 2.0.0-beta.21 → 2.0.0-beta.22

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.
package/lib/registerSw.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
+ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
7
8
  import { createStorageSlot } from '@docusaurus/theme-common';
8
9
  // First: read the env variables (provided by Webpack)
9
10
  /* eslint-disable prefer-destructuring */
@@ -12,23 +13,25 @@ const PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES = process.env
12
13
  .PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES;
13
14
  const PWA_DEBUG = process.env.PWA_DEBUG;
14
15
  /* eslint-enable prefer-destructuring */
15
- const debug = PWA_DEBUG; // Shortcut
16
- const MAX_MOBILE_WIDTH = 940;
16
+ const MAX_MOBILE_WIDTH = 996;
17
17
  const AppInstalledEventFiredStorage = createStorageSlot('docusaurus.pwa.event.appInstalled.fired');
18
- async function clearRegistrations() {
19
- const registrations = await navigator.serviceWorker.getRegistrations();
20
- if (debug) {
21
- console.log(`[Docusaurus-PWA][registerSw]: will unregister all service worker registrations`, registrations);
22
- }
23
- await Promise.all(registrations.map(async (registration) => {
24
- const result = await registration.unregister();
25
- if (debug) {
26
- console.log(`[Docusaurus-PWA][registerSw]: unregister() service worker registration`, registrations, result);
18
+ function debugLog(msg, obj) {
19
+ if (PWA_DEBUG) {
20
+ if (typeof obj === 'undefined') {
21
+ console.log(`[Docusaurus-PWA][registerSw]: ${msg}`);
22
+ }
23
+ else {
24
+ console.log(`[Docusaurus-PWA][registerSw]: ${msg}`, obj);
27
25
  }
28
- }));
29
- if (debug) {
30
- console.log(`[Docusaurus-PWA][registerSw]: unregistered all service worker registrations`, registrations);
31
26
  }
27
+ }
28
+ async function clearRegistrations() {
29
+ const registrations = await navigator.serviceWorker.getRegistrations();
30
+ debugLog('will unregister all service workers', { registrations });
31
+ await Promise.all(registrations.map((registration) => registration
32
+ .unregister()
33
+ .then((result) => debugLog('unregister service worker', { registration, result }))));
34
+ debugLog('unregistered all service workers', { registrations });
32
35
  window.location.reload();
33
36
  }
34
37
  /*
@@ -40,15 +43,15 @@ https://stackoverflow.com/questions/51735869/check-if-user-has-already-installed
40
43
  - getInstalledRelatedApps() is only supported in recent Chrome and does not seem to reliable either https://github.com/WICG/get-installed-related-apps
41
44
  - display-mode: standalone is not exactly the same concept, but looks like a decent fallback https://petelepage.com/blog/2019/07/is-my-pwa-installed/
42
45
  */
43
- async function isAppInstalledEventFired() {
46
+ function getIsAppInstalledEventFired() {
44
47
  return AppInstalledEventFiredStorage.get() === 'true';
45
48
  }
46
- async function isAppInstalledRelatedApps() {
47
- if ('getInstalledRelatedApps' in window.navigator) {
48
- const relatedApps = await navigator.getInstalledRelatedApps();
49
- return relatedApps.some((app) => app.platform === 'webapp');
49
+ async function getIsAppInstalledRelatedApps() {
50
+ if (!('getInstalledRelatedApps' in window.navigator)) {
51
+ return false;
50
52
  }
51
- return false;
53
+ const relatedApps = await navigator.getInstalledRelatedApps();
54
+ return relatedApps.some((app) => app.platform === 'webapp');
52
55
  }
53
56
  function isStandaloneDisplayMode() {
54
57
  return window.matchMedia('(display-mode: standalone)').matches;
@@ -57,169 +60,123 @@ const OfflineModeActivationStrategiesImplementations = {
57
60
  always: () => true,
58
61
  mobile: () => window.innerWidth <= MAX_MOBILE_WIDTH,
59
62
  saveData: () => !!navigator.connection?.saveData,
60
- appInstalled: async () => {
61
- const installedEventFired = await isAppInstalledEventFired();
62
- const installedRelatedApps = await isAppInstalledRelatedApps();
63
- return installedEventFired || installedRelatedApps;
64
- },
63
+ appInstalled: () => getIsAppInstalledEventFired() || getIsAppInstalledRelatedApps(),
65
64
  standalone: () => isStandaloneDisplayMode(),
66
65
  queryString: () => new URLSearchParams(window.location.search).get('offlineMode') === 'true',
67
66
  };
68
- async function isStrategyActive(strategyName) {
69
- return OfflineModeActivationStrategiesImplementations[strategyName]();
70
- }
71
67
  async function getActiveStrategies() {
72
- const activeStrategies = await Promise.all(PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES.map(async (strategyName) => {
73
- const isActive = await isStrategyActive(strategyName);
74
- return isActive ? strategyName : undefined;
75
- }));
68
+ const activeStrategies = await Promise.all(PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES.map((strategyName) => Promise.resolve(OfflineModeActivationStrategiesImplementations[strategyName]()).then((isActive) => (isActive ? strategyName : undefined))));
76
69
  return activeStrategies.filter(Boolean);
77
70
  }
78
- async function isOfflineModeEnabled() {
71
+ async function getIsOfflineModeEnabled() {
79
72
  const activeStrategies = await getActiveStrategies();
80
73
  const enabled = activeStrategies.length > 0;
81
- if (debug) {
82
- const logObject = {
83
- activeStrategies,
84
- availableStrategies: PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES,
85
- };
86
- if (enabled) {
87
- console.log('[Docusaurus-PWA][registerSw]: offline mode enabled, because of activation strategies', logObject);
88
- }
89
- else {
90
- console.log('[Docusaurus-PWA][registerSw]: offline mode disabled, because none of the offlineModeActivationStrategies could be used', logObject);
91
- }
92
- }
74
+ debugLog(enabled
75
+ ? 'offline mode enabled, because of activation strategies'
76
+ : 'offline mode disabled, because none of the offlineModeActivationStrategies could be used', {
77
+ activeStrategies,
78
+ availableStrategies: PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES,
79
+ });
93
80
  return enabled;
94
81
  }
95
82
  function createServiceWorkerUrl(params) {
96
83
  const paramsQueryString = JSON.stringify(params);
97
84
  const url = `${PWA_SERVICE_WORKER_URL}?params=${encodeURIComponent(paramsQueryString)}`;
98
- if (debug) {
99
- console.log(`[Docusaurus-PWA][registerSw]: service worker url`, {
100
- url,
101
- params,
102
- });
103
- }
85
+ debugLog('service worker url', { url, params });
104
86
  return url;
105
87
  }
106
88
  async function registerSW() {
107
- const { Workbox } = await import('workbox-window');
108
- const offlineMode = await isOfflineModeEnabled();
109
- const url = createServiceWorkerUrl({ offlineMode, debug });
89
+ const [{ Workbox }, offlineMode] = await Promise.all([
90
+ import('workbox-window'),
91
+ getIsOfflineModeEnabled(),
92
+ ]);
93
+ const url = createServiceWorkerUrl({ offlineMode, debug: PWA_DEBUG });
110
94
  const wb = new Workbox(url);
111
- const registration = await wb.register();
112
95
  const sendSkipWaiting = () => wb.messageSW({ type: 'SKIP_WAITING' });
113
- const handleServiceWorkerWaiting = async () => {
114
- if (debug) {
115
- console.log('[Docusaurus-PWA][registerSw]: handleServiceWorkerWaiting');
116
- }
96
+ const handleServiceWorkerWaiting = () => {
97
+ debugLog('handleServiceWorkerWaiting');
117
98
  // Immediately load new service worker when files aren't cached
118
99
  if (!offlineMode) {
119
- sendSkipWaiting();
120
- }
121
- else {
122
- const renderReloadPopup = (await import('./renderReloadPopup')).default;
123
- await renderReloadPopup({
124
- onReload() {
125
- wb.addEventListener('controlling', () => {
126
- window.location.reload();
127
- });
128
- sendSkipWaiting();
129
- },
130
- });
100
+ return sendSkipWaiting();
131
101
  }
102
+ return import('./renderReloadPopup.js').then(({ renderReloadPopup }) => renderReloadPopup({
103
+ onReload() {
104
+ wb.addEventListener('controlling', () => {
105
+ window.location.reload();
106
+ });
107
+ sendSkipWaiting();
108
+ },
109
+ }));
132
110
  };
133
- if (debug && registration) {
134
- if (registration.active) {
135
- console.log('[Docusaurus-PWA][registerSw]: registration.active', registration);
136
- }
137
- if (registration.installing) {
138
- console.log('[Docusaurus-PWA][registerSw]: registration.installing', registration);
139
- }
140
- if (registration.waiting) {
141
- console.log('[Docusaurus-PWA][registerSw]: registration.waiting', registration);
142
- }
143
- }
144
111
  // Update the current service worker when the next one has finished
145
112
  // installing and transitions to waiting state.
146
113
  wb.addEventListener('waiting', (event) => {
147
- if (debug) {
148
- console.log('[Docusaurus-PWA][registerSw]: event waiting', event);
149
- }
150
- handleServiceWorkerWaiting();
114
+ debugLog('event waiting', { event });
115
+ void handleServiceWorkerWaiting();
151
116
  });
152
117
  // Update current service worker if the next one finishes installing and
153
118
  // moves to waiting state in another tab.
154
119
  // @ts-expect-error: not present in the API typings anymore
155
120
  wb.addEventListener('externalwaiting', (event) => {
156
- if (debug) {
157
- console.log('[Docusaurus-PWA][registerSw]: event externalwaiting', event);
158
- }
159
- handleServiceWorkerWaiting();
121
+ debugLog('event externalwaiting', { event });
122
+ void handleServiceWorkerWaiting();
160
123
  });
161
- // Update service worker if the next one is already in the waiting state.
162
- // This happens when the user doesn't click on `reload` in the popup.
163
- if (registration?.waiting) {
164
- await handleServiceWorkerWaiting();
124
+ const registration = await wb.register();
125
+ if (registration) {
126
+ if (registration.active) {
127
+ debugLog('registration.active', { registration });
128
+ }
129
+ if (registration.installing) {
130
+ debugLog('registration.installing', { registration });
131
+ }
132
+ if (registration.waiting) {
133
+ debugLog('registration.waiting', { registration });
134
+ // Update service worker if the next one is already in the waiting
135
+ // state. This happens when the user doesn't click on `reload` in
136
+ // the popup.
137
+ await handleServiceWorkerWaiting();
138
+ }
165
139
  }
166
140
  }
167
141
  // TODO these events still works in chrome but have been removed from the spec
168
142
  // in 2019! See https://github.com/w3c/manifest/pull/836
169
143
  function addLegacyAppInstalledEventsListeners() {
170
- if (typeof window !== 'undefined') {
171
- if (debug) {
172
- console.log('[Docusaurus-PWA][registerSw]: addLegacyAppInstalledEventsListeners');
173
- }
174
- window.addEventListener('appinstalled', async (event) => {
175
- if (debug) {
176
- console.log('[Docusaurus-PWA][registerSw]: event appinstalled', event);
177
- }
178
- AppInstalledEventFiredStorage.set('true');
179
- if (debug) {
180
- console.log("[Docusaurus-PWA][registerSw]: AppInstalledEventFiredStorage.set('true')");
181
- }
182
- // After the app is installed, we register a service worker with the path
183
- // `/sw?enabled`. Since the previous service worker was `/sw`, it'll be
184
- // treated as a new one. The previous registration will need to be
185
- // cleared, otherwise the reload popup will show.
186
- await clearRegistrations();
187
- });
188
- // TODO this event still works in chrome but has been removed from the spec
189
- // in 2019!!!
190
- window.addEventListener('beforeinstallprompt', async (event) => {
191
- if (debug) {
192
- console.log('[Docusaurus-PWA][registerSw]: event beforeinstallprompt', event);
193
- }
194
- // TODO instead of default browser install UI, show custom docusaurus
195
- // prompt?
196
- // event.preventDefault();
197
- if (debug) {
198
- console.log('[Docusaurus-PWA][registerSw]: AppInstalledEventFiredStorage.get()', AppInstalledEventFiredStorage.get());
199
- }
200
- if (AppInstalledEventFiredStorage.get()) {
201
- AppInstalledEventFiredStorage.del();
202
- if (debug) {
203
- console.log('[Docusaurus-PWA][registerSw]: AppInstalledEventFiredStorage.del()');
204
- }
205
- // After uninstalling the app, if the user doesn't clear all data, then
206
- // the previous service worker will continue serving cached files. We
207
- // need to clear registrations and reload, otherwise the popup shows.
208
- await clearRegistrations();
209
- }
210
- });
211
- if (debug) {
212
- console.log('[Docusaurus-PWA][registerSw]: legacy appinstalled and beforeinstallprompt event listeners installed');
144
+ debugLog('addLegacyAppInstalledEventsListeners');
145
+ window.addEventListener('appinstalled', (event) => {
146
+ debugLog('event appinstalled', { event });
147
+ AppInstalledEventFiredStorage.set('true');
148
+ debugLog("AppInstalledEventFiredStorage.set('true')");
149
+ // After the app is installed, we register a service worker with the path
150
+ // `/sw?enabled`. Since the previous service worker was `/sw`, it'll be
151
+ // treated as a new one. The previous registration will need to be
152
+ // cleared, otherwise the reload popup will show.
153
+ void clearRegistrations();
154
+ });
155
+ // TODO this event still works in chrome but has been removed from the spec
156
+ // in 2019!!!
157
+ window.addEventListener('beforeinstallprompt', (event) => {
158
+ debugLog('event beforeinstallprompt', { event });
159
+ // TODO instead of default browser install UI, show custom docusaurus
160
+ // prompt?
161
+ // event.preventDefault();
162
+ const appInstalledEventFired = AppInstalledEventFiredStorage.get();
163
+ debugLog('AppInstalledEventFiredStorage.get()', { appInstalledEventFired });
164
+ if (appInstalledEventFired) {
165
+ AppInstalledEventFiredStorage.del();
166
+ debugLog('AppInstalledEventFiredStorage.del()');
167
+ // After uninstalling the app, if the user doesn't clear all data, then
168
+ // the previous service worker will continue serving cached files. We
169
+ // need to clear registrations and reload, otherwise the popup shows.
170
+ void clearRegistrations();
213
171
  }
214
- }
172
+ });
173
+ debugLog('legacy appinstalled and beforeinstallprompt event listeners installed');
215
174
  }
216
175
  /*
217
176
  Init code to run on the client!
218
177
  */
219
- if (typeof window !== 'undefined') {
220
- if (debug) {
221
- console.log('[Docusaurus-PWA][registerSw]: debug mode enabled');
222
- }
178
+ if (ExecutionEnvironment.canUseDOM) {
179
+ debugLog('debug mode enabled');
223
180
  if ('serviceWorker' in navigator) {
224
181
  // First: add the listeners asap/synchronously
225
182
  addLegacyAppInstalledEventsListeners();
@@ -5,4 +5,4 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { Props } from '@theme/PwaReloadPopup';
8
- export default function renderReloadPopup(props: Props): Promise<void>;
8
+ export declare function renderReloadPopup(props: Props): Promise<void>;
@@ -14,8 +14,9 @@ const createContainer = () => {
14
14
  document.body.appendChild(container);
15
15
  return container;
16
16
  };
17
- export default async function renderReloadPopup(props) {
18
- const container = getContainer() || createContainer();
19
- const ReloadPopup = (await import('@theme/PwaReloadPopup')).default;
20
- ReactDOM.render(<ReloadPopup {...props}/>, container);
17
+ export function renderReloadPopup(props) {
18
+ const container = getContainer() ?? createContainer();
19
+ return import('@theme/PwaReloadPopup').then(({ default: ReloadPopup }) => {
20
+ ReactDOM.render(<ReloadPopup {...props}/>, container);
21
+ });
21
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-pwa",
3
- "version": "2.0.0-beta.21",
3
+ "version": "2.0.0-beta.22",
4
4
  "description": "Docusaurus Plugin to add PWA support.",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/plugin-pwa.d.ts",
@@ -20,26 +20,27 @@
20
20
  },
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "@babel/core": "^7.18.2",
24
- "@babel/preset-env": "^7.18.2",
25
- "@docusaurus/core": "2.0.0-beta.21",
26
- "@docusaurus/theme-common": "2.0.0-beta.21",
27
- "@docusaurus/theme-translations": "2.0.0-beta.21",
28
- "@docusaurus/utils": "2.0.0-beta.21",
29
- "@docusaurus/utils-validation": "2.0.0-beta.21",
23
+ "@babel/core": "^7.18.6",
24
+ "@babel/preset-env": "^7.18.6",
25
+ "@docusaurus/core": "2.0.0-beta.22",
26
+ "@docusaurus/theme-common": "2.0.0-beta.22",
27
+ "@docusaurus/theme-translations": "2.0.0-beta.22",
28
+ "@docusaurus/types": "2.0.0-beta.22",
29
+ "@docusaurus/utils": "2.0.0-beta.22",
30
+ "@docusaurus/utils-validation": "2.0.0-beta.22",
30
31
  "babel-loader": "^8.2.5",
31
- "clsx": "^1.1.1",
32
- "core-js": "^3.22.7",
33
- "terser-webpack-plugin": "^5.3.1",
32
+ "clsx": "^1.2.0",
33
+ "core-js": "^3.23.3",
34
+ "terser-webpack-plugin": "^5.3.3",
34
35
  "tslib": "^2.4.0",
35
- "webpack": "^5.72.1",
36
+ "webpack": "^5.73.0",
36
37
  "webpack-merge": "^5.8.0",
37
38
  "workbox-build": "^6.5.3",
38
39
  "workbox-precaching": "^6.5.3",
39
40
  "workbox-window": "^6.5.3"
40
41
  },
41
42
  "devDependencies": {
42
- "@docusaurus/module-type-aliases": "2.0.0-beta.21",
43
+ "@docusaurus/module-type-aliases": "2.0.0-beta.22",
43
44
  "fs-extra": "^10.1.0"
44
45
  },
45
46
  "peerDependencies": {
@@ -49,5 +50,5 @@
49
50
  "engines": {
50
51
  "node": ">=16.14"
51
52
  },
52
- "gitHead": "69ac49fc6909517f13615ee40290c4bd00c39df4"
53
+ "gitHead": "daf9e462c4eebb7ac26a940932311f987e768f87"
53
54
  }
package/src/deps.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ // TODO incompatible declaration file: https://github.com/unjs/webpackbar/pull/108
9
+ declare module 'webpackbar' {
10
+ import webpack from 'webpack';
11
+
12
+ export default class WebpackBarPlugin extends webpack.ProgressPlugin {
13
+ constructor(options: {name: string; color?: string});
14
+ }
15
+ }
package/src/registerSw.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
8
9
  import {createStorageSlot} from '@docusaurus/theme-common';
9
10
 
10
11
  // First: read the env variables (provided by Webpack)
@@ -15,40 +16,42 @@ const PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES = process.env
15
16
  const PWA_DEBUG = process.env.PWA_DEBUG;
16
17
  /* eslint-enable prefer-destructuring */
17
18
 
18
- const debug = PWA_DEBUG; // Shortcut
19
-
20
- const MAX_MOBILE_WIDTH = 940;
19
+ const MAX_MOBILE_WIDTH = 996;
21
20
 
22
21
  const AppInstalledEventFiredStorage = createStorageSlot(
23
22
  'docusaurus.pwa.event.appInstalled.fired',
24
23
  );
25
24
 
25
+ declare global {
26
+ interface Navigator {
27
+ getInstalledRelatedApps: () => Promise<{platform: string}[]>;
28
+ connection?: {effectiveType: string; saveData: boolean};
29
+ }
30
+ }
31
+
32
+ function debugLog(msg: string, obj?: unknown) {
33
+ if (PWA_DEBUG) {
34
+ if (typeof obj === 'undefined') {
35
+ console.log(`[Docusaurus-PWA][registerSw]: ${msg}`);
36
+ } else {
37
+ console.log(`[Docusaurus-PWA][registerSw]: ${msg}`, obj);
38
+ }
39
+ }
40
+ }
41
+
26
42
  async function clearRegistrations() {
27
43
  const registrations = await navigator.serviceWorker.getRegistrations();
28
- if (debug) {
29
- console.log(
30
- `[Docusaurus-PWA][registerSw]: will unregister all service worker registrations`,
31
- registrations,
32
- );
33
- }
44
+ debugLog('will unregister all service workers', {registrations});
34
45
  await Promise.all(
35
- registrations.map(async (registration) => {
36
- const result = await registration.unregister();
37
- if (debug) {
38
- console.log(
39
- `[Docusaurus-PWA][registerSw]: unregister() service worker registration`,
40
- registrations,
41
- result,
42
- );
43
- }
44
- }),
46
+ registrations.map((registration) =>
47
+ registration
48
+ .unregister()
49
+ .then((result) =>
50
+ debugLog('unregister service worker', {registration, result}),
51
+ ),
52
+ ),
45
53
  );
46
- if (debug) {
47
- console.log(
48
- `[Docusaurus-PWA][registerSw]: unregistered all service worker registrations`,
49
- registrations,
50
- );
51
- }
54
+ debugLog('unregistered all service workers', {registrations});
52
55
  window.location.reload();
53
56
  }
54
57
 
@@ -61,23 +64,16 @@ https://stackoverflow.com/questions/51735869/check-if-user-has-already-installed
61
64
  - getInstalledRelatedApps() is only supported in recent Chrome and does not seem to reliable either https://github.com/WICG/get-installed-related-apps
62
65
  - display-mode: standalone is not exactly the same concept, but looks like a decent fallback https://petelepage.com/blog/2019/07/is-my-pwa-installed/
63
66
  */
64
- async function isAppInstalledEventFired() {
67
+ function getIsAppInstalledEventFired() {
65
68
  return AppInstalledEventFiredStorage.get() === 'true';
66
69
  }
67
70
 
68
- declare global {
69
- interface Navigator {
70
- getInstalledRelatedApps: () => Promise<{platform: string}[]>;
71
- connection?: {effectiveType: string; saveData: boolean};
72
- }
73
- }
74
-
75
- async function isAppInstalledRelatedApps() {
76
- if ('getInstalledRelatedApps' in window.navigator) {
77
- const relatedApps = await navigator.getInstalledRelatedApps();
78
- return relatedApps.some((app) => app.platform === 'webapp');
71
+ async function getIsAppInstalledRelatedApps() {
72
+ if (!('getInstalledRelatedApps' in window.navigator)) {
73
+ return false;
79
74
  }
80
- return false;
75
+ const relatedApps = await navigator.getInstalledRelatedApps();
76
+ return relatedApps.some((app) => app.platform === 'webapp');
81
77
  }
82
78
  function isStandaloneDisplayMode() {
83
79
  return window.matchMedia('(display-mode: standalone)').matches;
@@ -87,52 +83,36 @@ const OfflineModeActivationStrategiesImplementations = {
87
83
  always: () => true,
88
84
  mobile: () => window.innerWidth <= MAX_MOBILE_WIDTH,
89
85
  saveData: () => !!navigator.connection?.saveData,
90
- appInstalled: async () => {
91
- const installedEventFired = await isAppInstalledEventFired();
92
- const installedRelatedApps = await isAppInstalledRelatedApps();
93
- return installedEventFired || installedRelatedApps;
94
- },
86
+ appInstalled: () =>
87
+ getIsAppInstalledEventFired() || getIsAppInstalledRelatedApps(),
95
88
  standalone: () => isStandaloneDisplayMode(),
96
89
  queryString: () =>
97
90
  new URLSearchParams(window.location.search).get('offlineMode') === 'true',
98
91
  };
99
92
 
100
- async function isStrategyActive(
101
- strategyName: keyof typeof OfflineModeActivationStrategiesImplementations,
102
- ) {
103
- return OfflineModeActivationStrategiesImplementations[strategyName]();
104
- }
105
-
106
93
  async function getActiveStrategies() {
107
94
  const activeStrategies = await Promise.all(
108
- PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES.map(async (strategyName) => {
109
- const isActive = await isStrategyActive(strategyName);
110
- return isActive ? strategyName : undefined;
111
- }),
95
+ PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES.map((strategyName) =>
96
+ Promise.resolve(
97
+ OfflineModeActivationStrategiesImplementations[strategyName](),
98
+ ).then((isActive) => (isActive ? strategyName : undefined)),
99
+ ),
112
100
  );
113
101
  return activeStrategies.filter(Boolean);
114
102
  }
115
103
 
116
- async function isOfflineModeEnabled() {
104
+ async function getIsOfflineModeEnabled() {
117
105
  const activeStrategies = await getActiveStrategies();
118
106
  const enabled = activeStrategies.length > 0;
119
- if (debug) {
120
- const logObject = {
107
+ debugLog(
108
+ enabled
109
+ ? 'offline mode enabled, because of activation strategies'
110
+ : 'offline mode disabled, because none of the offlineModeActivationStrategies could be used',
111
+ {
121
112
  activeStrategies,
122
113
  availableStrategies: PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES,
123
- };
124
- if (enabled) {
125
- console.log(
126
- '[Docusaurus-PWA][registerSw]: offline mode enabled, because of activation strategies',
127
- logObject,
128
- );
129
- } else {
130
- console.log(
131
- '[Docusaurus-PWA][registerSw]: offline mode disabled, because none of the offlineModeActivationStrategies could be used',
132
- logObject,
133
- );
134
- }
135
- }
114
+ },
115
+ );
136
116
  return enabled;
137
117
  }
138
118
 
@@ -141,170 +121,111 @@ function createServiceWorkerUrl(params: object) {
141
121
  const url = `${PWA_SERVICE_WORKER_URL}?params=${encodeURIComponent(
142
122
  paramsQueryString,
143
123
  )}`;
144
- if (debug) {
145
- console.log(`[Docusaurus-PWA][registerSw]: service worker url`, {
146
- url,
147
- params,
148
- });
149
- }
124
+ debugLog('service worker url', {url, params});
150
125
  return url;
151
126
  }
152
127
 
153
128
  async function registerSW() {
154
- const {Workbox} = await import('workbox-window');
155
-
156
- const offlineMode = await isOfflineModeEnabled();
157
-
158
- const url = createServiceWorkerUrl({offlineMode, debug});
129
+ const [{Workbox}, offlineMode] = await Promise.all([
130
+ import('workbox-window'),
131
+ getIsOfflineModeEnabled(),
132
+ ]);
133
+ const url = createServiceWorkerUrl({offlineMode, debug: PWA_DEBUG});
159
134
  const wb = new Workbox(url);
160
-
161
- const registration = await wb.register();
162
-
163
135
  const sendSkipWaiting = () => wb.messageSW({type: 'SKIP_WAITING'});
164
-
165
- const handleServiceWorkerWaiting = async () => {
166
- if (debug) {
167
- console.log('[Docusaurus-PWA][registerSw]: handleServiceWorkerWaiting');
168
- }
136
+ const handleServiceWorkerWaiting = () => {
137
+ debugLog('handleServiceWorkerWaiting');
169
138
  // Immediately load new service worker when files aren't cached
170
139
  if (!offlineMode) {
171
- sendSkipWaiting();
172
- } else {
173
- const renderReloadPopup = (await import('./renderReloadPopup')).default;
174
- await renderReloadPopup({
140
+ return sendSkipWaiting();
141
+ }
142
+ return import('./renderReloadPopup.js').then(({renderReloadPopup}) =>
143
+ renderReloadPopup({
175
144
  onReload() {
176
145
  wb.addEventListener('controlling', () => {
177
146
  window.location.reload();
178
147
  });
179
148
  sendSkipWaiting();
180
149
  },
181
- });
182
- }
150
+ }),
151
+ );
183
152
  };
184
-
185
- if (debug && registration) {
186
- if (registration.active) {
187
- console.log(
188
- '[Docusaurus-PWA][registerSw]: registration.active',
189
- registration,
190
- );
191
- }
192
- if (registration.installing) {
193
- console.log(
194
- '[Docusaurus-PWA][registerSw]: registration.installing',
195
- registration,
196
- );
197
- }
198
- if (registration.waiting) {
199
- console.log(
200
- '[Docusaurus-PWA][registerSw]: registration.waiting',
201
- registration,
202
- );
203
- }
204
- }
205
-
206
153
  // Update the current service worker when the next one has finished
207
154
  // installing and transitions to waiting state.
208
155
  wb.addEventListener('waiting', (event) => {
209
- if (debug) {
210
- console.log('[Docusaurus-PWA][registerSw]: event waiting', event);
211
- }
212
- handleServiceWorkerWaiting();
156
+ debugLog('event waiting', {event});
157
+ void handleServiceWorkerWaiting();
213
158
  });
214
-
215
159
  // Update current service worker if the next one finishes installing and
216
160
  // moves to waiting state in another tab.
217
161
  // @ts-expect-error: not present in the API typings anymore
218
162
  wb.addEventListener('externalwaiting', (event) => {
219
- if (debug) {
220
- console.log('[Docusaurus-PWA][registerSw]: event externalwaiting', event);
221
- }
222
- handleServiceWorkerWaiting();
163
+ debugLog('event externalwaiting', {event});
164
+ void handleServiceWorkerWaiting();
223
165
  });
224
-
225
- // Update service worker if the next one is already in the waiting state.
226
- // This happens when the user doesn't click on `reload` in the popup.
227
- if (registration?.waiting) {
228
- await handleServiceWorkerWaiting();
166
+ const registration = await wb.register();
167
+ if (registration) {
168
+ if (registration.active) {
169
+ debugLog('registration.active', {registration});
170
+ }
171
+ if (registration.installing) {
172
+ debugLog('registration.installing', {registration});
173
+ }
174
+ if (registration.waiting) {
175
+ debugLog('registration.waiting', {registration});
176
+ // Update service worker if the next one is already in the waiting
177
+ // state. This happens when the user doesn't click on `reload` in
178
+ // the popup.
179
+ await handleServiceWorkerWaiting();
180
+ }
229
181
  }
230
182
  }
231
183
 
232
184
  // TODO these events still works in chrome but have been removed from the spec
233
185
  // in 2019! See https://github.com/w3c/manifest/pull/836
234
186
  function addLegacyAppInstalledEventsListeners() {
235
- if (typeof window !== 'undefined') {
236
- if (debug) {
237
- console.log(
238
- '[Docusaurus-PWA][registerSw]: addLegacyAppInstalledEventsListeners',
239
- );
240
- }
241
-
242
- window.addEventListener('appinstalled', async (event) => {
243
- if (debug) {
244
- console.log('[Docusaurus-PWA][registerSw]: event appinstalled', event);
245
- }
246
-
247
- AppInstalledEventFiredStorage.set('true');
248
- if (debug) {
249
- console.log(
250
- "[Docusaurus-PWA][registerSw]: AppInstalledEventFiredStorage.set('true')",
251
- );
252
- }
253
-
254
- // After the app is installed, we register a service worker with the path
255
- // `/sw?enabled`. Since the previous service worker was `/sw`, it'll be
256
- // treated as a new one. The previous registration will need to be
257
- // cleared, otherwise the reload popup will show.
258
- await clearRegistrations();
259
- });
260
-
261
- // TODO this event still works in chrome but has been removed from the spec
262
- // in 2019!!!
263
- window.addEventListener('beforeinstallprompt', async (event) => {
264
- if (debug) {
265
- console.log(
266
- '[Docusaurus-PWA][registerSw]: event beforeinstallprompt',
267
- event,
268
- );
269
- }
270
- // TODO instead of default browser install UI, show custom docusaurus
271
- // prompt?
272
- // event.preventDefault();
273
- if (debug) {
274
- console.log(
275
- '[Docusaurus-PWA][registerSw]: AppInstalledEventFiredStorage.get()',
276
- AppInstalledEventFiredStorage.get(),
277
- );
278
- }
279
- if (AppInstalledEventFiredStorage.get()) {
280
- AppInstalledEventFiredStorage.del();
281
- if (debug) {
282
- console.log(
283
- '[Docusaurus-PWA][registerSw]: AppInstalledEventFiredStorage.del()',
284
- );
285
- }
286
- // After uninstalling the app, if the user doesn't clear all data, then
287
- // the previous service worker will continue serving cached files. We
288
- // need to clear registrations and reload, otherwise the popup shows.
289
- await clearRegistrations();
290
- }
291
- });
187
+ debugLog('addLegacyAppInstalledEventsListeners');
188
+
189
+ window.addEventListener('appinstalled', (event) => {
190
+ debugLog('event appinstalled', {event});
191
+ AppInstalledEventFiredStorage.set('true');
192
+ debugLog("AppInstalledEventFiredStorage.set('true')");
193
+ // After the app is installed, we register a service worker with the path
194
+ // `/sw?enabled`. Since the previous service worker was `/sw`, it'll be
195
+ // treated as a new one. The previous registration will need to be
196
+ // cleared, otherwise the reload popup will show.
197
+ void clearRegistrations();
198
+ });
292
199
 
293
- if (debug) {
294
- console.log(
295
- '[Docusaurus-PWA][registerSw]: legacy appinstalled and beforeinstallprompt event listeners installed',
296
- );
200
+ // TODO this event still works in chrome but has been removed from the spec
201
+ // in 2019!!!
202
+ window.addEventListener('beforeinstallprompt', (event) => {
203
+ debugLog('event beforeinstallprompt', {event});
204
+ // TODO instead of default browser install UI, show custom docusaurus
205
+ // prompt?
206
+ // event.preventDefault();
207
+ const appInstalledEventFired = AppInstalledEventFiredStorage.get();
208
+ debugLog('AppInstalledEventFiredStorage.get()', {appInstalledEventFired});
209
+ if (appInstalledEventFired) {
210
+ AppInstalledEventFiredStorage.del();
211
+ debugLog('AppInstalledEventFiredStorage.del()');
212
+ // After uninstalling the app, if the user doesn't clear all data, then
213
+ // the previous service worker will continue serving cached files. We
214
+ // need to clear registrations and reload, otherwise the popup shows.
215
+ void clearRegistrations();
297
216
  }
298
- }
217
+ });
218
+
219
+ debugLog(
220
+ 'legacy appinstalled and beforeinstallprompt event listeners installed',
221
+ );
299
222
  }
300
223
 
301
224
  /*
302
225
  Init code to run on the client!
303
226
  */
304
- if (typeof window !== 'undefined') {
305
- if (debug) {
306
- console.log('[Docusaurus-PWA][registerSw]: debug mode enabled');
307
- }
227
+ if (ExecutionEnvironment.canUseDOM) {
228
+ debugLog('debug mode enabled');
308
229
 
309
230
  if ('serviceWorker' in navigator) {
310
231
  // First: add the listeners asap/synchronously
@@ -20,8 +20,9 @@ const createContainer = () => {
20
20
  return container;
21
21
  };
22
22
 
23
- export default async function renderReloadPopup(props: Props): Promise<void> {
24
- const container = getContainer() || createContainer();
25
- const ReloadPopup = (await import('@theme/PwaReloadPopup')).default;
26
- ReactDOM.render(<ReloadPopup {...props} />, container);
23
+ export function renderReloadPopup(props: Props): Promise<void> {
24
+ const container = getContainer() ?? createContainer();
25
+ return import('@theme/PwaReloadPopup').then(({default: ReloadPopup}) => {
26
+ ReactDOM.render(<ReloadPopup {...props} />, container);
27
+ });
27
28
  }