@interface-technologies/check-for-js-bundle-update-saga 4.5.0 → 5.0.0
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/dist/checkForJsBundleUpdateSaga.d.ts +50 -50
- package/dist/checkForJsBundleUpdateSaga.js +116 -117
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/package.json +10 -12
@@ -1,50 +1,50 @@
|
|
1
|
-
import moment from 'moment-timezone';
|
2
|
-
import { SagaIterator } from 'redux-saga';
|
3
|
-
/** @internal */
|
4
|
-
export declare function getIndexHtml(): Promise<string | undefined>;
|
5
|
-
/** @internal */
|
6
|
-
export declare function reload(): void;
|
7
|
-
export interface CheckForJsBundleUpdateSagaOptions {
|
8
|
-
delayDuration?: moment.Duration;
|
9
|
-
onError(e: unknown): void;
|
10
|
-
bundleSrcPattern?: RegExp;
|
11
|
-
}
|
12
|
-
/**
|
13
|
-
* Periodically fetches `/` (`index.html`) to check if a new JavaScript bundle has been
|
14
|
-
* released.
|
15
|
-
*
|
16
|
-
* If the bundle has been updated, the user is prompted to refresh the page.
|
17
|
-
* After 3 alerts are shown, the page is forcibly refreshed.
|
18
|
-
*
|
19
|
-
* Don't enable this in development!
|
20
|
-
*
|
21
|
-
* Your `index.html` must contain a script tag like:
|
22
|
-
*
|
23
|
-
* ```html
|
24
|
-
* <script src="app.23e590a23b49.js"></script>
|
25
|
-
* ```
|
26
|
-
*
|
27
|
-
* or
|
28
|
-
*
|
29
|
-
* ```html
|
30
|
-
* <script src="dist/app.js?v=Gq0JHtehvL9fMpV"></script>
|
31
|
-
* ```
|
32
|
-
*
|
33
|
-
* `checkForJsBundleUpdateSaga` will compare the `src` attribute of the script tag.
|
34
|
-
*
|
35
|
-
* An example of using `checkForJsBundleUpdateSaga` from your TypeScript code:
|
36
|
-
*
|
37
|
-
* ```
|
38
|
-
* export function* myCheckForJsBundleUpdateSaga(): SagaIterator<void> {
|
39
|
-
* if (process.env.NODE_ENV === 'development') return
|
40
|
-
*
|
41
|
-
* function onError(e: unknown): void {
|
42
|
-
* console.error(e)
|
43
|
-
* Bugsnag.notify(e)
|
44
|
-
* }
|
45
|
-
*
|
46
|
-
* yield call(checkForJsBundleUpdateSaga, { onError })
|
47
|
-
* }
|
48
|
-
* ```
|
49
|
-
*/
|
50
|
-
export declare function checkForJsBundleUpdateSaga({ delayDuration, onError, bundleSrcPattern, }: CheckForJsBundleUpdateSagaOptions): SagaIterator<void>;
|
1
|
+
import moment from 'moment-timezone';
|
2
|
+
import { SagaIterator } from 'redux-saga';
|
3
|
+
/** @internal */
|
4
|
+
export declare function getIndexHtml(): Promise<string | undefined>;
|
5
|
+
/** @internal */
|
6
|
+
export declare function reload(): void;
|
7
|
+
export interface CheckForJsBundleUpdateSagaOptions {
|
8
|
+
delayDuration?: moment.Duration;
|
9
|
+
onError(e: unknown): void;
|
10
|
+
bundleSrcPattern?: RegExp;
|
11
|
+
}
|
12
|
+
/**
|
13
|
+
* Periodically fetches `/` (`index.html`) to check if a new JavaScript bundle has been
|
14
|
+
* released.
|
15
|
+
*
|
16
|
+
* If the bundle has been updated, the user is prompted to refresh the page.
|
17
|
+
* After 3 alerts are shown, the page is forcibly refreshed.
|
18
|
+
*
|
19
|
+
* Don't enable this in development!
|
20
|
+
*
|
21
|
+
* Your `index.html` must contain a script tag like:
|
22
|
+
*
|
23
|
+
* ```html
|
24
|
+
* <script src="app.23e590a23b49.js"></script>
|
25
|
+
* ```
|
26
|
+
*
|
27
|
+
* or
|
28
|
+
*
|
29
|
+
* ```html
|
30
|
+
* <script src="dist/app.js?v=Gq0JHtehvL9fMpV"></script>
|
31
|
+
* ```
|
32
|
+
*
|
33
|
+
* `checkForJsBundleUpdateSaga` will compare the `src` attribute of the script tag.
|
34
|
+
*
|
35
|
+
* An example of using `checkForJsBundleUpdateSaga` from your TypeScript code:
|
36
|
+
*
|
37
|
+
* ```
|
38
|
+
* export function* myCheckForJsBundleUpdateSaga(): SagaIterator<void> {
|
39
|
+
* if (process.env.NODE_ENV === 'development') return
|
40
|
+
*
|
41
|
+
* function onError(e: unknown): void {
|
42
|
+
* console.error(e)
|
43
|
+
* Bugsnag.notify(e)
|
44
|
+
* }
|
45
|
+
*
|
46
|
+
* yield call(checkForJsBundleUpdateSaga, { onError })
|
47
|
+
* }
|
48
|
+
* ```
|
49
|
+
*/
|
50
|
+
export declare function checkForJsBundleUpdateSaga({ delayDuration, onError, bundleSrcPattern, }: CheckForJsBundleUpdateSagaOptions): SagaIterator<void>;
|
@@ -1,117 +1,116 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
-
};
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.
|
7
|
-
|
8
|
-
|
9
|
-
const
|
10
|
-
const
|
11
|
-
const
|
12
|
-
const
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
function getBundleSrcFromDocument(doc, bundleSrcPattern) {
|
31
|
-
var _a;
|
32
|
-
const scripts = Array.from(doc.getElementsByTagName('script'));
|
33
|
-
for (const script of scripts) {
|
34
|
-
const parts = (_a = script.src) === null || _a === void 0 ? void 0 : _a.split('/');
|
35
|
-
if (parts.length === 0)
|
36
|
-
continue;
|
37
|
-
const src = parts[parts.length - 1];
|
38
|
-
if (bundleSrcPattern.test(src))
|
39
|
-
return src;
|
40
|
-
}
|
41
|
-
return undefined;
|
42
|
-
}
|
43
|
-
/**
|
44
|
-
* Periodically fetches `/` (`index.html`) to check if a new JavaScript bundle has been
|
45
|
-
* released.
|
46
|
-
*
|
47
|
-
* If the bundle has been updated, the user is prompted to refresh the page.
|
48
|
-
* After 3 alerts are shown, the page is forcibly refreshed.
|
49
|
-
*
|
50
|
-
* Don't enable this in development!
|
51
|
-
*
|
52
|
-
* Your `index.html` must contain a script tag like:
|
53
|
-
*
|
54
|
-
* ```html
|
55
|
-
* <script src="app.23e590a23b49.js"></script>
|
56
|
-
* ```
|
57
|
-
*
|
58
|
-
* or
|
59
|
-
*
|
60
|
-
* ```html
|
61
|
-
* <script src="dist/app.js?v=Gq0JHtehvL9fMpV"></script>
|
62
|
-
* ```
|
63
|
-
*
|
64
|
-
* `checkForJsBundleUpdateSaga` will compare the `src` attribute of the script tag.
|
65
|
-
*
|
66
|
-
* An example of using `checkForJsBundleUpdateSaga` from your TypeScript code:
|
67
|
-
*
|
68
|
-
* ```
|
69
|
-
* export function* myCheckForJsBundleUpdateSaga(): SagaIterator<void> {
|
70
|
-
* if (process.env.NODE_ENV === 'development') return
|
71
|
-
*
|
72
|
-
* function onError(e: unknown): void {
|
73
|
-
* console.error(e)
|
74
|
-
* Bugsnag.notify(e)
|
75
|
-
* }
|
76
|
-
*
|
77
|
-
* yield call(checkForJsBundleUpdateSaga, { onError })
|
78
|
-
* }
|
79
|
-
* ```
|
80
|
-
*/
|
81
|
-
function* checkForJsBundleUpdateSaga({ delayDuration = defaultDelayDuration, onError, bundleSrcPattern = /app\.\S+\.js/, }) {
|
82
|
-
const bundleSrc = getBundleSrcFromDocument(document, bundleSrcPattern);
|
83
|
-
if (!bundleSrc) {
|
84
|
-
onError(new Error('Could not get bundle src from current document.'));
|
85
|
-
return;
|
86
|
-
}
|
87
|
-
yield (0, effects_1.delay)(delayDuration.asMilliseconds());
|
88
|
-
let alertShownCount = 0;
|
89
|
-
for (;;) {
|
90
|
-
try {
|
91
|
-
const indexHtml = (yield (0, effects_1.call)(getIndexHtml));
|
92
|
-
if (indexHtml) {
|
93
|
-
const retrievedDocument = new DOMParser().parseFromString(indexHtml, 'text/html');
|
94
|
-
const retrievedBundleSrc = getBundleSrcFromDocument(retrievedDocument, bundleSrcPattern);
|
95
|
-
if (!retrievedBundleSrc) {
|
96
|
-
onError('Could not get bundle src from retrieved document.');
|
97
|
-
return;
|
98
|
-
}
|
99
|
-
if (bundleSrc !== retrievedBundleSrc) {
|
100
|
-
const content = ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { children: "Please save your work and refresh the page." }), (0, jsx_runtime_1.jsx)("p", { className: "mb-0", children: "You may encounter errors if you do not refresh the page." })] }));
|
101
|
-
if (alertShownCount >= forceRefreshAfterAlertCount) {
|
102
|
-
window.onbeforeunload = null;
|
103
|
-
yield (0, effects_1.call)(reload);
|
104
|
-
return;
|
105
|
-
}
|
106
|
-
yield (0, effects_1.call)(iti_react_1.alert, content, { title: 'Website Update Available!' });
|
107
|
-
alertShownCount += 1;
|
108
|
-
}
|
109
|
-
}
|
110
|
-
}
|
111
|
-
catch (e) {
|
112
|
-
onError(e);
|
113
|
-
}
|
114
|
-
yield (0, effects_1.delay)(delayDuration.asMilliseconds());
|
115
|
-
}
|
116
|
-
}
|
117
|
-
exports.checkForJsBundleUpdateSaga = checkForJsBundleUpdateSaga;
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.getIndexHtml = getIndexHtml;
|
7
|
+
exports.reload = reload;
|
8
|
+
exports.checkForJsBundleUpdateSaga = checkForJsBundleUpdateSaga;
|
9
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
10
|
+
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
11
|
+
const effects_1 = require("redux-saga/effects");
|
12
|
+
const iti_react_1 = require("@interface-technologies/iti-react");
|
13
|
+
const defaultDelayDuration = moment_timezone_1.default.duration(4, 'minutes');
|
14
|
+
const forceRefreshAfterAlertCount = 3;
|
15
|
+
/** @internal */
|
16
|
+
function getIndexHtml() {
|
17
|
+
return (fetch('/')
|
18
|
+
.then((response) => {
|
19
|
+
if (!response.ok)
|
20
|
+
return undefined;
|
21
|
+
return response.text();
|
22
|
+
})
|
23
|
+
// If fetch throws a TypeError for some weird reason, also return undefined
|
24
|
+
.catch(() => undefined));
|
25
|
+
}
|
26
|
+
/** @internal */
|
27
|
+
function reload() {
|
28
|
+
window.location.reload();
|
29
|
+
}
|
30
|
+
function getBundleSrcFromDocument(doc, bundleSrcPattern) {
|
31
|
+
var _a;
|
32
|
+
const scripts = Array.from(doc.getElementsByTagName('script'));
|
33
|
+
for (const script of scripts) {
|
34
|
+
const parts = (_a = script.src) === null || _a === void 0 ? void 0 : _a.split('/');
|
35
|
+
if (parts.length === 0)
|
36
|
+
continue;
|
37
|
+
const src = parts[parts.length - 1];
|
38
|
+
if (bundleSrcPattern.test(src))
|
39
|
+
return src;
|
40
|
+
}
|
41
|
+
return undefined;
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Periodically fetches `/` (`index.html`) to check if a new JavaScript bundle has been
|
45
|
+
* released.
|
46
|
+
*
|
47
|
+
* If the bundle has been updated, the user is prompted to refresh the page.
|
48
|
+
* After 3 alerts are shown, the page is forcibly refreshed.
|
49
|
+
*
|
50
|
+
* Don't enable this in development!
|
51
|
+
*
|
52
|
+
* Your `index.html` must contain a script tag like:
|
53
|
+
*
|
54
|
+
* ```html
|
55
|
+
* <script src="app.23e590a23b49.js"></script>
|
56
|
+
* ```
|
57
|
+
*
|
58
|
+
* or
|
59
|
+
*
|
60
|
+
* ```html
|
61
|
+
* <script src="dist/app.js?v=Gq0JHtehvL9fMpV"></script>
|
62
|
+
* ```
|
63
|
+
*
|
64
|
+
* `checkForJsBundleUpdateSaga` will compare the `src` attribute of the script tag.
|
65
|
+
*
|
66
|
+
* An example of using `checkForJsBundleUpdateSaga` from your TypeScript code:
|
67
|
+
*
|
68
|
+
* ```
|
69
|
+
* export function* myCheckForJsBundleUpdateSaga(): SagaIterator<void> {
|
70
|
+
* if (process.env.NODE_ENV === 'development') return
|
71
|
+
*
|
72
|
+
* function onError(e: unknown): void {
|
73
|
+
* console.error(e)
|
74
|
+
* Bugsnag.notify(e)
|
75
|
+
* }
|
76
|
+
*
|
77
|
+
* yield call(checkForJsBundleUpdateSaga, { onError })
|
78
|
+
* }
|
79
|
+
* ```
|
80
|
+
*/
|
81
|
+
function* checkForJsBundleUpdateSaga({ delayDuration = defaultDelayDuration, onError, bundleSrcPattern = /app\.\S+\.js/, }) {
|
82
|
+
const bundleSrc = getBundleSrcFromDocument(document, bundleSrcPattern);
|
83
|
+
if (!bundleSrc) {
|
84
|
+
onError(new Error('Could not get bundle src from current document.'));
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
yield (0, effects_1.delay)(delayDuration.asMilliseconds());
|
88
|
+
let alertShownCount = 0;
|
89
|
+
for (;;) {
|
90
|
+
try {
|
91
|
+
const indexHtml = (yield (0, effects_1.call)(getIndexHtml));
|
92
|
+
if (indexHtml) {
|
93
|
+
const retrievedDocument = new DOMParser().parseFromString(indexHtml, 'text/html');
|
94
|
+
const retrievedBundleSrc = getBundleSrcFromDocument(retrievedDocument, bundleSrcPattern);
|
95
|
+
if (!retrievedBundleSrc) {
|
96
|
+
onError('Could not get bundle src from retrieved document.');
|
97
|
+
return;
|
98
|
+
}
|
99
|
+
if (bundleSrc !== retrievedBundleSrc) {
|
100
|
+
const content = ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { children: "Please save your work and refresh the page." }), (0, jsx_runtime_1.jsx)("p", { className: "mb-0", children: "You may encounter errors if you do not refresh the page." })] }));
|
101
|
+
if (alertShownCount >= forceRefreshAfterAlertCount) {
|
102
|
+
window.onbeforeunload = null;
|
103
|
+
yield (0, effects_1.call)(reload);
|
104
|
+
return;
|
105
|
+
}
|
106
|
+
yield (0, effects_1.call)(iti_react_1.alert, content, { title: 'Website Update Available!' });
|
107
|
+
alertShownCount += 1;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
catch (e) {
|
112
|
+
onError(e);
|
113
|
+
}
|
114
|
+
yield (0, effects_1.delay)(delayDuration.asMilliseconds());
|
115
|
+
}
|
116
|
+
}
|
package/dist/index.d.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
export { checkForJsBundleUpdateSaga } from './checkForJsBundleUpdateSaga';
|
2
|
-
export type { CheckForJsBundleUpdateSagaOptions } from './checkForJsBundleUpdateSaga';
|
1
|
+
export { checkForJsBundleUpdateSaga } from './checkForJsBundleUpdateSaga';
|
2
|
+
export type { CheckForJsBundleUpdateSagaOptions } from './checkForJsBundleUpdateSaga';
|
package/dist/index.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.checkForJsBundleUpdateSaga = void 0;
|
4
|
-
var checkForJsBundleUpdateSaga_1 = require("./checkForJsBundleUpdateSaga");
|
5
|
-
Object.defineProperty(exports, "checkForJsBundleUpdateSaga", { enumerable: true, get: function () { return checkForJsBundleUpdateSaga_1.checkForJsBundleUpdateSaga; } });
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.checkForJsBundleUpdateSaga = void 0;
|
4
|
+
var checkForJsBundleUpdateSaga_1 = require("./checkForJsBundleUpdateSaga");
|
5
|
+
Object.defineProperty(exports, "checkForJsBundleUpdateSaga", { enumerable: true, get: function () { return checkForJsBundleUpdateSaga_1.checkForJsBundleUpdateSaga; } });
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@interface-technologies/check-for-js-bundle-update-saga",
|
3
|
-
"version": "
|
3
|
+
"version": "5.0.0",
|
4
4
|
"description": "Redux saga for checking if a JavaScript app has been deployed.",
|
5
5
|
"homepage": "https://github.com/srmagura/iti-react",
|
6
6
|
"repository": {
|
@@ -11,25 +11,23 @@
|
|
11
11
|
"author": "Interface Technologies, Inc.",
|
12
12
|
"main": "dist/index.js",
|
13
13
|
"types": "dist/index.d.ts",
|
14
|
-
"typedocMain": "src/index.ts",
|
15
14
|
"files": [
|
16
15
|
"dist"
|
17
16
|
],
|
18
17
|
"sideEffects": false,
|
19
18
|
"prettier": "@interface-technologies/prettier-config",
|
20
19
|
"dependencies": {
|
21
|
-
"@types/react": "^
|
22
|
-
"moment-timezone": "^0.5.
|
23
|
-
"redux-saga": "^1.
|
20
|
+
"@types/react": "^18.3.4",
|
21
|
+
"moment-timezone": "^0.5.45",
|
22
|
+
"redux-saga": "^1.3.0"
|
24
23
|
},
|
25
24
|
"devDependencies": {
|
26
|
-
"@interface-technologies/iti-react": "
|
27
|
-
"@interface-technologies/tsconfig": "
|
28
|
-
"@redux-saga/is": "^1.1.
|
29
|
-
"@redux-saga/symbols": "^1.1.
|
30
|
-
"
|
31
|
-
"
|
32
|
-
"redux-saga-test-plan": "^4.0.4"
|
25
|
+
"@interface-technologies/iti-react": "5.0.0",
|
26
|
+
"@interface-technologies/tsconfig": "5.0.0",
|
27
|
+
"@redux-saga/is": "^1.1.3",
|
28
|
+
"@redux-saga/symbols": "^1.1.3",
|
29
|
+
"react": "^18.3.1",
|
30
|
+
"redux-saga-test-plan": "^4.0.6"
|
33
31
|
},
|
34
32
|
"peerDependencies": {
|
35
33
|
"@interface-technologies/iti-react": "^4.3.8",
|