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

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/sw.js CHANGED
@@ -5,143 +5,107 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  /* eslint-disable no-restricted-globals */
8
-
9
- import {PrecacheController} from 'workbox-precaching';
10
-
8
+ import { PrecacheController } from 'workbox-precaching';
11
9
  function parseSwParams() {
12
- const params = JSON.parse(
13
- new URLSearchParams(self.location.search).get('params'),
14
- );
15
- if (params.debug) {
16
- console.log('[Docusaurus-PWA][SW]: Service Worker params:', params);
17
- }
18
- return params;
10
+ const params = JSON.parse(new URLSearchParams(self.location.search).get('params'));
11
+ if (params.debug) {
12
+ console.log('[Docusaurus-PWA][SW]: Service Worker params:', params);
13
+ }
14
+ return params;
19
15
  }
20
-
21
16
  // Doc advises against dynamic imports in SW
22
17
  // https://developers.google.com/web/tools/workbox/guides/using-bundlers#code_splitting_and_dynamic_imports
23
18
  // https://twitter.com/sebastienlorber/status/1280155204575518720
24
19
  // but looks it's working fine as it's inlined by webpack, need to double check
25
20
  async function runSWCustomCode(params) {
26
- if (process.env.PWA_SW_CUSTOM) {
27
- const customSW = await import(process.env.PWA_SW_CUSTOM);
28
- if (typeof customSW.default === 'function') {
29
- customSW.default(params);
30
- } else if (params.debug) {
31
- console.warn(
32
- '[Docusaurus-PWA][SW]: swCustom should have a default export function',
33
- );
21
+ if (process.env.PWA_SW_CUSTOM) {
22
+ const customSW = await import(process.env.PWA_SW_CUSTOM);
23
+ if (typeof customSW.default === 'function') {
24
+ customSW.default(params);
25
+ }
26
+ else if (params.debug) {
27
+ console.warn('[Docusaurus-PWA][SW]: swCustom should have a default export function');
28
+ }
34
29
  }
35
- }
36
30
  }
37
-
38
31
  /**
39
32
  * Gets different possible variations for a request URL. Similar to
40
33
  * https://git.io/JvixK
41
- *
42
- * @param {string} url
43
34
  */
44
35
  function getPossibleURLs(url) {
45
- const possibleURLs = [];
46
- const urlObject = new URL(url, self.location.href);
47
-
48
- if (urlObject.origin !== self.location.origin) {
49
- return possibleURLs;
50
- }
51
-
52
- // Ignore search params and hash
53
- urlObject.search = '';
54
- urlObject.hash = '';
55
-
56
- // /blog.html
57
- possibleURLs.push(urlObject.href);
58
-
59
- // /blog/ => /blog/index.html
60
- if (urlObject.pathname.endsWith('/')) {
61
- possibleURLs.push(`${urlObject.href}index.html`);
62
- } else {
63
- // /blog => /blog/index.html
64
- possibleURLs.push(`${urlObject.href}/index.html`);
65
- }
66
-
67
- return possibleURLs;
36
+ const urlObject = new URL(url, self.location.href);
37
+ if (urlObject.origin !== self.location.origin) {
38
+ return [];
39
+ }
40
+ // Ignore search params and hash
41
+ urlObject.search = '';
42
+ urlObject.hash = '';
43
+ return [
44
+ // /blog.html
45
+ urlObject.href,
46
+ // /blog/ => /blog/index.html
47
+ // /blog => /blog/index.html
48
+ `${urlObject.href}${urlObject.pathname.endsWith('/') ? '' : '/'}index.html`,
49
+ ];
68
50
  }
69
-
70
51
  (async () => {
71
- const params = parseSwParams();
72
-
73
- // eslint-disable-next-line no-underscore-dangle
74
- const precacheManifest = self.__WB_MANIFEST;
75
- const controller = new PrecacheController({
76
- // Safer to turn this true?
77
- fallbackToNetwork: true,
78
- });
79
-
80
- if (params.offlineMode) {
81
- controller.addToCacheList(precacheManifest);
82
- if (params.debug) {
83
- console.log('[Docusaurus-PWA][SW]: addToCacheList', {
84
- precacheManifest,
85
- });
86
- }
87
- }
88
-
89
- await runSWCustomCode(params);
90
-
91
- self.addEventListener('install', (event) => {
92
- if (params.debug) {
93
- console.log('[Docusaurus-PWA][SW]: install event', {
94
- event,
95
- });
96
- }
97
- event.waitUntil(controller.install(event));
98
- });
99
-
100
- self.addEventListener('activate', (event) => {
101
- if (params.debug) {
102
- console.log('[Docusaurus-PWA][SW]: activate event', {
103
- event,
104
- });
105
- }
106
- event.waitUntil(controller.activate(event));
107
- });
108
-
109
- self.addEventListener('fetch', async (event) => {
52
+ const params = parseSwParams();
53
+ // eslint-disable-next-line no-underscore-dangle
54
+ const precacheManifest = self.__WB_MANIFEST;
55
+ const controller = new PrecacheController({
56
+ // Safer to turn this true?
57
+ fallbackToNetwork: true,
58
+ });
110
59
  if (params.offlineMode) {
111
- const requestURL = event.request.url;
112
- const possibleURLs = getPossibleURLs(requestURL);
113
- for (let i = 0; i < possibleURLs.length; i += 1) {
114
- const possibleURL = possibleURLs[i];
115
- const cacheKey = controller.getCacheKeyForURL(possibleURL);
116
- if (cacheKey) {
117
- const cachedResponse = caches.match(cacheKey);
118
- if (params.debug) {
119
- console.log('[Docusaurus-PWA][SW]: serving cached asset', {
120
- requestURL,
121
- possibleURL,
122
- possibleURLs,
123
- cacheKey,
124
- cachedResponse,
125
- });
126
- }
127
- event.respondWith(cachedResponse);
128
- break;
60
+ controller.addToCacheList(precacheManifest);
61
+ if (params.debug) {
62
+ console.log('[Docusaurus-PWA][SW]: addToCacheList', { precacheManifest });
129
63
  }
130
- }
131
- }
132
- });
133
-
134
- self.addEventListener('message', async (event) => {
135
- if (params.debug) {
136
- console.log('[Docusaurus-PWA][SW]: message event', {
137
- event,
138
- });
139
- }
140
-
141
- const type = event.data?.type;
142
-
143
- if (type === 'SKIP_WAITING') {
144
- self.skipWaiting();
145
64
  }
146
- });
65
+ await runSWCustomCode(params);
66
+ self.addEventListener('install', (event) => {
67
+ if (params.debug) {
68
+ console.log('[Docusaurus-PWA][SW]: install event', { event });
69
+ }
70
+ event.waitUntil(controller.install(event));
71
+ });
72
+ self.addEventListener('activate', (event) => {
73
+ if (params.debug) {
74
+ console.log('[Docusaurus-PWA][SW]: activate event', { event });
75
+ }
76
+ event.waitUntil(controller.activate(event));
77
+ });
78
+ self.addEventListener('fetch', async (event) => {
79
+ if (params.offlineMode) {
80
+ const requestURL = event.request.url;
81
+ const possibleURLs = getPossibleURLs(requestURL);
82
+ for (const possibleURL of possibleURLs) {
83
+ const cacheKey = controller.getCacheKeyForURL(possibleURL);
84
+ if (cacheKey) {
85
+ const cachedResponse = caches.match(cacheKey);
86
+ if (params.debug) {
87
+ console.log('[Docusaurus-PWA][SW]: serving cached asset', {
88
+ requestURL,
89
+ possibleURL,
90
+ possibleURLs,
91
+ cacheKey,
92
+ cachedResponse,
93
+ });
94
+ }
95
+ event.respondWith(cachedResponse);
96
+ break;
97
+ }
98
+ }
99
+ }
100
+ });
101
+ self.addEventListener('message', async (event) => {
102
+ if (params.debug) {
103
+ console.log('[Docusaurus-PWA][SW]: message event', { event });
104
+ }
105
+ const type = event.data?.type;
106
+ if (type === 'SKIP_WAITING') {
107
+ // lib def bug, see https://github.com/microsoft/TypeScript/issues/14877
108
+ self.skipWaiting();
109
+ }
110
+ });
147
111
  })();
@@ -4,35 +4,51 @@
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 React, { useState } from 'react';
7
+ import React, {useState} from 'react';
8
8
  import clsx from 'clsx';
9
- import Translate, { translate } from '@docusaurus/Translate';
9
+ import Translate, {translate} from '@docusaurus/Translate';
10
10
  import styles from './styles.module.css';
11
- export default function PwaReloadPopup({ onReload }) {
12
- const [isVisible, setIsVisible] = useState(true);
13
- return (isVisible && (<div className={clsx('alert', 'alert--secondary', styles.popup)}>
11
+ export default function PwaReloadPopup({onReload}) {
12
+ const [isVisible, setIsVisible] = useState(true);
13
+ return (
14
+ isVisible && (
15
+ <div className={clsx('alert', 'alert--secondary', styles.popup)}>
14
16
  <p>
15
- <Translate id="theme.PwaReloadPopup.info" description="The text for PWA reload popup">
17
+ <Translate
18
+ id="theme.PwaReloadPopup.info"
19
+ description="The text for PWA reload popup">
16
20
  New version available
17
21
  </Translate>
18
22
  </p>
19
23
  <div className={styles.buttonContainer}>
20
- <button className="button button--link" type="button" onClick={() => {
21
- setIsVisible(false);
22
- onReload();
23
- }}>
24
- <Translate id="theme.PwaReloadPopup.refreshButtonText" description="The text for PWA reload button">
24
+ <button
25
+ className="button button--link"
26
+ type="button"
27
+ onClick={() => {
28
+ setIsVisible(false);
29
+ onReload();
30
+ }}>
31
+ <Translate
32
+ id="theme.PwaReloadPopup.refreshButtonText"
33
+ description="The text for PWA reload button">
25
34
  Refresh
26
35
  </Translate>
27
36
  </button>
28
37
 
29
- <button aria-label={translate({
30
- id: 'theme.PwaReloadPopup.closeButtonAriaLabel',
31
- message: 'Close',
32
- description: 'The ARIA label for close button of PWA reload popup',
33
- })} className="close" type="button" onClick={() => setIsVisible(false)}>
38
+ <button
39
+ aria-label={translate({
40
+ id: 'theme.PwaReloadPopup.closeButtonAriaLabel',
41
+ message: 'Close',
42
+ description:
43
+ 'The ARIA label for close button of PWA reload popup',
44
+ })}
45
+ className="close"
46
+ type="button"
47
+ onClick={() => setIsVisible(false)}>
34
48
  <span aria-hidden="true">×</span>
35
49
  </button>
36
50
  </div>
37
- </div>));
51
+ </div>
52
+ )
53
+ );
38
54
  }
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-pwa",
3
- "version": "2.0.0-beta.20",
3
+ "version": "2.0.0-beta.21",
4
4
  "description": "Docusaurus Plugin to add PWA support.",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/plugin-pwa.d.ts",
7
7
  "scripts": {
8
- "build": "yarn build:server && yarn build:browser && yarn build:copy",
9
- "build:server": "tsc --project tsconfig.server.json",
10
- "build:browser": "tsc --project tsconfig.browser.json",
11
- "build:copy": "node copyUntypedFiles.mjs"
8
+ "build": "tsc --build && node ../../admin/scripts/copyUntypedFiles.js && prettier --config ../../.prettierrc --write \"lib/theme/**/*.js\"",
9
+ "watch": "run-p -c copy:watch build:watch",
10
+ "build:watch": "tsc --build --watch",
11
+ "copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
12
12
  },
13
13
  "publishConfig": {
14
14
  "access": "public"
@@ -20,31 +20,34 @@
20
20
  },
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "@babel/core": "^7.17.10",
24
- "@babel/preset-env": "^7.17.10",
25
- "@docusaurus/core": "2.0.0-beta.20",
26
- "@docusaurus/theme-common": "2.0.0-beta.20",
27
- "@docusaurus/theme-translations": "2.0.0-beta.20",
28
- "@docusaurus/utils": "2.0.0-beta.20",
29
- "@docusaurus/utils-validation": "2.0.0-beta.20",
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",
30
30
  "babel-loader": "^8.2.5",
31
31
  "clsx": "^1.1.1",
32
- "core-js": "^3.22.3",
32
+ "core-js": "^3.22.7",
33
33
  "terser-webpack-plugin": "^5.3.1",
34
34
  "tslib": "^2.4.0",
35
- "webpack": "^5.72.0",
35
+ "webpack": "^5.72.1",
36
36
  "webpack-merge": "^5.8.0",
37
37
  "workbox-build": "^6.5.3",
38
38
  "workbox-precaching": "^6.5.3",
39
39
  "workbox-window": "^6.5.3"
40
40
  },
41
41
  "devDependencies": {
42
- "@docusaurus/module-type-aliases": "2.0.0-beta.20",
42
+ "@docusaurus/module-type-aliases": "2.0.0-beta.21",
43
43
  "fs-extra": "^10.1.0"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react": "^16.8.4 || ^17.0.0",
47
47
  "react-dom": "^16.8.4 || ^17.0.0"
48
48
  },
49
- "gitHead": "ed5cdba401a5948e187e927039b142a0decc702d"
49
+ "engines": {
50
+ "node": ">=16.14"
51
+ },
52
+ "gitHead": "69ac49fc6909517f13615ee40290c4bd00c39df4"
50
53
  }
package/src/index.ts CHANGED
@@ -5,18 +5,16 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import type {HtmlTags, LoadContext, Plugin} from '@docusaurus/types';
9
- import type {PluginOptions} from '@docusaurus/plugin-pwa';
10
- import {normalizeUrl} from '@docusaurus/utils';
11
- import {compile} from '@docusaurus/core/lib/webpack/utils';
12
- import LogPlugin from '@docusaurus/core/lib/webpack/plugins/LogPlugin';
13
- import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
14
-
15
8
  import path from 'path';
16
9
  import webpack, {type Configuration} from 'webpack';
17
10
  import Terser from 'terser-webpack-plugin';
18
-
19
11
  import {injectManifest} from 'workbox-build';
12
+ import {normalizeUrl} from '@docusaurus/utils';
13
+ import {compile} from '@docusaurus/core/lib/webpack/utils';
14
+ import LogPlugin from '@docusaurus/core/lib/webpack/plugins/LogPlugin';
15
+ import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
16
+ import type {HtmlTags, LoadContext, Plugin} from '@docusaurus/types';
17
+ import type {PluginOptions} from '@docusaurus/plugin-pwa';
20
18
 
21
19
  const isProd = process.env.NODE_ENV === 'production';
22
20
 
@@ -54,7 +52,6 @@ export default function pluginPWA(
54
52
  debug,
55
53
  offlineModeActivationStrategies,
56
54
  injectManifestConfig,
57
- reloadPopup,
58
55
  pwaHead,
59
56
  swCustom,
60
57
  swRegister,
@@ -91,12 +88,11 @@ export default function pluginPWA(
91
88
  new webpack.EnvironmentPlugin({
92
89
  PWA_DEBUG: debug,
93
90
  PWA_SERVICE_WORKER_URL: path.posix.resolve(
94
- `${config.output?.publicPath || '/'}`,
91
+ `${(config.output?.publicPath as string) || '/'}`,
95
92
  'sw.js',
96
93
  ),
97
94
  PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES:
98
95
  offlineModeActivationStrategies,
99
- PWA_RELOAD_POPUP: reloadPopup,
100
96
  }),
101
97
  ],
102
98
  };
@@ -104,7 +100,7 @@ export default function pluginPWA(
104
100
 
105
101
  injectHtmlTags() {
106
102
  const headTags: HtmlTags = [];
107
- if (isProd && pwaHead) {
103
+ if (isProd) {
108
104
  pwaHead.forEach(({tagName, ...attributes}) => {
109
105
  (['href', 'content'] as const).forEach((attribute) => {
110
106
  const attributeValue = attributes[attribute];
@@ -162,7 +158,7 @@ export default function pluginPWA(
162
158
  plugins: [
163
159
  new webpack.EnvironmentPlugin({
164
160
  // Fallback value required with Webpack 5
165
- PWA_SW_CUSTOM: swCustom || '',
161
+ PWA_SW_CUSTOM: swCustom ?? '',
166
162
  }),
167
163
  new LogPlugin({
168
164
  name: 'Service Worker',
@@ -191,7 +187,7 @@ export default function pluginPWA(
191
187
  '**/*.{png,jpg,jpeg,gif,svg,ico}',
192
188
  '**/*.{woff,woff2,eot,ttf,otf}',
193
189
  // @ts-expect-error: internal API?
194
- ...(injectManifest.globPatterns ?? []),
190
+ ...((injectManifest.globPatterns as string[] | undefined) ?? []),
195
191
  ],
196
192
  // Those attributes are not overrideable
197
193
  swDest,
package/src/options.ts CHANGED
@@ -20,10 +20,9 @@ const DEFAULT_OPTIONS = {
20
20
  pwaHead: [],
21
21
  swCustom: undefined,
22
22
  swRegister: './registerSw.js',
23
- reloadPopup: '@theme/PwaReloadPopup',
24
23
  };
25
24
 
26
- const Schema = Joi.object({
25
+ const optionsSchema = Joi.object<PluginOptions>({
27
26
  debug: Joi.bool().default(DEFAULT_OPTIONS.debug),
28
27
  offlineModeActivationStrategies: Joi.array()
29
28
  .items(
@@ -49,14 +48,16 @@ const Schema = Joi.object({
49
48
  swRegister: Joi.alternatives()
50
49
  .try(Joi.string(), Joi.bool().valid(false))
51
50
  .default(DEFAULT_OPTIONS.swRegister),
52
- reloadPopup: Joi.alternatives()
53
- .try(Joi.string(), Joi.bool().valid(false))
54
- .default(DEFAULT_OPTIONS.reloadPopup),
51
+ // @ts-expect-error: forbidden
52
+ reloadPopup: Joi.any().forbidden().messages({
53
+ 'any.unknown':
54
+ 'The reloadPopup option is removed in favor of swizzling. See https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-pwa#customizing-reload-popup for how to customize the reload popup using swizzling.',
55
+ }),
55
56
  });
56
57
 
57
58
  export function validateOptions({
58
59
  validate,
59
60
  options,
60
61
  }: OptionValidationContext<PluginOptions, PluginOptions>): PluginOptions {
61
- return validate(Schema, options);
62
+ return validate(optionsSchema, options);
62
63
  }
@@ -46,16 +46,6 @@ declare module '@docusaurus/plugin-pwa' {
46
46
  * @see https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.injectManifest
47
47
  */
48
48
  injectManifestConfig: InjectManifestOptions;
49
- /**
50
- * Module path to reload popup component. This popup is rendered when a new
51
- * service worker is waiting to be installed, and we suggest a reload to
52
- * the user.
53
- *
54
- * Passing `false` will disable the popup, but this is not recommended:
55
- * users won't have a way to get up-to-date content.
56
- * @see {@link @theme/PwaReloadPopup}
57
- */
58
- reloadPopup: string | false;
59
49
  /**
60
50
  * Array of objects containing `tagName` and key-value pairs for attributes
61
51
  * to inject into the `<head>` tag. Technically you can inject any head tag
@@ -9,10 +9,9 @@ import {createStorageSlot} from '@docusaurus/theme-common';
9
9
 
10
10
  // First: read the env variables (provided by Webpack)
11
11
  /* eslint-disable prefer-destructuring */
12
- const PWA_SERVICE_WORKER_URL = process.env.PWA_SERVICE_WORKER_URL;
13
- const PWA_RELOAD_POPUP = process.env.PWA_RELOAD_POPUP;
14
- const PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES =
15
- process.env.PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES;
12
+ const PWA_SERVICE_WORKER_URL = process.env.PWA_SERVICE_WORKER_URL!;
13
+ const PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES = process.env
14
+ .PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES as unknown as (keyof typeof OfflineModeActivationStrategiesImplementations)[];
16
15
  const PWA_DEBUG = process.env.PWA_DEBUG;
17
16
  /* eslint-enable prefer-destructuring */
18
17
 
@@ -34,7 +33,7 @@ async function clearRegistrations() {
34
33
  }
35
34
  await Promise.all(
36
35
  registrations.map(async (registration) => {
37
- const result = await registration?.registration?.unregister();
36
+ const result = await registration.unregister();
38
37
  if (debug) {
39
38
  console.log(
40
39
  `[Docusaurus-PWA][registerSw]: unregister() service worker registration`,
@@ -65,6 +64,14 @@ https://stackoverflow.com/questions/51735869/check-if-user-has-already-installed
65
64
  async function isAppInstalledEventFired() {
66
65
  return AppInstalledEventFiredStorage.get() === 'true';
67
66
  }
67
+
68
+ declare global {
69
+ interface Navigator {
70
+ getInstalledRelatedApps: () => Promise<{platform: string}[]>;
71
+ connection?: {effectiveType: string; saveData: boolean};
72
+ }
73
+ }
74
+
68
75
  async function isAppInstalledRelatedApps() {
69
76
  if ('getInstalledRelatedApps' in window.navigator) {
70
77
  const relatedApps = await navigator.getInstalledRelatedApps();
@@ -90,7 +97,9 @@ const OfflineModeActivationStrategiesImplementations = {
90
97
  new URLSearchParams(window.location.search).get('offlineMode') === 'true',
91
98
  };
92
99
 
93
- async function isStrategyActive(strategyName) {
100
+ async function isStrategyActive(
101
+ strategyName: keyof typeof OfflineModeActivationStrategiesImplementations,
102
+ ) {
94
103
  return OfflineModeActivationStrategiesImplementations[strategyName]();
95
104
  }
96
105
 
@@ -127,7 +136,7 @@ async function isOfflineModeEnabled() {
127
136
  return enabled;
128
137
  }
129
138
 
130
- function createServiceWorkerUrl(params) {
139
+ function createServiceWorkerUrl(params: object) {
131
140
  const paramsQueryString = JSON.stringify(params);
132
141
  const url = `${PWA_SERVICE_WORKER_URL}?params=${encodeURIComponent(
133
142
  paramsQueryString,
@@ -160,7 +169,7 @@ async function registerSW() {
160
169
  // Immediately load new service worker when files aren't cached
161
170
  if (!offlineMode) {
162
171
  sendSkipWaiting();
163
- } else if (PWA_RELOAD_POPUP) {
172
+ } else {
164
173
  const renderReloadPopup = (await import('./renderReloadPopup')).default;
165
174
  await renderReloadPopup({
166
175
  onReload() {
@@ -173,7 +182,7 @@ async function registerSW() {
173
182
  }
174
183
  };
175
184
 
176
- if (debug) {
185
+ if (debug && registration) {
177
186
  if (registration.active) {
178
187
  console.log(
179
188
  '[Docusaurus-PWA][registerSw]: registration.active',
@@ -205,6 +214,7 @@ async function registerSW() {
205
214
 
206
215
  // Update current service worker if the next one finishes installing and
207
216
  // moves to waiting state in another tab.
217
+ // @ts-expect-error: not present in the API typings anymore
208
218
  wb.addEventListener('externalwaiting', (event) => {
209
219
  if (debug) {
210
220
  console.log('[Docusaurus-PWA][registerSw]: event externalwaiting', event);
@@ -214,7 +224,7 @@ async function registerSW() {
214
224
 
215
225
  // Update service worker if the next one is already in the waiting state.
216
226
  // This happens when the user doesn't click on `reload` in the popup.
217
- if (registration.waiting) {
227
+ if (registration?.waiting) {
218
228
  await handleServiceWorkerWaiting();
219
229
  }
220
230
  }
@@ -301,6 +311,6 @@ if (typeof window !== 'undefined') {
301
311
  addLegacyAppInstalledEventsListeners();
302
312
 
303
313
  // Then try to register the SW using lazy/dynamic imports
304
- registerSW().catch((e) => console.error('registerSW failed', e));
314
+ registerSW().catch((e: unknown) => console.error('registerSW failed', e));
305
315
  }
306
316
  }
@@ -6,7 +6,8 @@
6
6
  */
7
7
 
8
8
  import React from 'react';
9
- import {render} from 'react-dom';
9
+ import ReactDOM from 'react-dom';
10
+ import type {Props} from '@theme/PwaReloadPopup';
10
11
 
11
12
  const POPUP_CONTAINER_ID = 'pwa-popup-container';
12
13
 
@@ -19,8 +20,8 @@ const createContainer = () => {
19
20
  return container;
20
21
  };
21
22
 
22
- export default async function renderReloadPopup(props) {
23
+ export default async function renderReloadPopup(props: Props): Promise<void> {
23
24
  const container = getContainer() || createContainer();
24
- const {default: ReloadPopup} = await import(process.env.PWA_RELOAD_POPUP);
25
- render(<ReloadPopup {...props} />, container);
25
+ const ReloadPopup = (await import('@theme/PwaReloadPopup')).default;
26
+ ReactDOM.render(<ReloadPopup {...props} />, container);
26
27
  }