@interface-technologies/check-for-js-bundle-update-saga 4.2.1 → 4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/checkForJsBundleUpdateSaga.d.ts +50 -50
- package/dist/checkForJsBundleUpdateSaga.js +117 -117
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/package.json +4 -4
@@ -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,117 @@
|
|
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.checkForJsBundleUpdateSaga = exports.reload = exports.getIndexHtml = void 0;
|
7
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
8
|
-
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
9
|
-
const effects_1 = require("redux-saga/effects");
|
10
|
-
const iti_react_1 = require("@interface-technologies/iti-react");
|
11
|
-
const defaultDelayDuration = moment_timezone_1.default.duration(4, 'minutes');
|
12
|
-
const forceRefreshAfterAlertCount = 3;
|
13
|
-
/** @internal */
|
14
|
-
function getIndexHtml() {
|
15
|
-
return (fetch('/')
|
16
|
-
.then((response) => {
|
17
|
-
if (!response.ok)
|
18
|
-
return undefined;
|
19
|
-
return response.text();
|
20
|
-
})
|
21
|
-
// If fetch throws a TypeError for some weird reason, also return undefined
|
22
|
-
.catch(() => undefined));
|
23
|
-
}
|
24
|
-
exports.getIndexHtml = getIndexHtml;
|
25
|
-
/** @internal */
|
26
|
-
function reload() {
|
27
|
-
window.location.reload();
|
28
|
-
}
|
29
|
-
exports.reload = reload;
|
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." }, void 0), (0, jsx_runtime_1.jsx)("p", { className: "mb-0", children: "You may encounter errors if you do not refresh the page." }, void 0)] }, void 0));
|
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.checkForJsBundleUpdateSaga = exports.reload = exports.getIndexHtml = void 0;
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
8
|
+
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
9
|
+
const effects_1 = require("redux-saga/effects");
|
10
|
+
const iti_react_1 = require("@interface-technologies/iti-react");
|
11
|
+
const defaultDelayDuration = moment_timezone_1.default.duration(4, 'minutes');
|
12
|
+
const forceRefreshAfterAlertCount = 3;
|
13
|
+
/** @internal */
|
14
|
+
function getIndexHtml() {
|
15
|
+
return (fetch('/')
|
16
|
+
.then((response) => {
|
17
|
+
if (!response.ok)
|
18
|
+
return undefined;
|
19
|
+
return response.text();
|
20
|
+
})
|
21
|
+
// If fetch throws a TypeError for some weird reason, also return undefined
|
22
|
+
.catch(() => undefined));
|
23
|
+
}
|
24
|
+
exports.getIndexHtml = getIndexHtml;
|
25
|
+
/** @internal */
|
26
|
+
function reload() {
|
27
|
+
window.location.reload();
|
28
|
+
}
|
29
|
+
exports.reload = reload;
|
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." }, void 0), (0, jsx_runtime_1.jsx)("p", { className: "mb-0", children: "You may encounter errors if you do not refresh the page." }, void 0)] }, void 0));
|
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;
|
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": "4.2.
|
3
|
+
"version": "4.2.2",
|
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": {
|
@@ -23,8 +23,8 @@
|
|
23
23
|
"redux-saga": "^1.1.3"
|
24
24
|
},
|
25
25
|
"devDependencies": {
|
26
|
-
"@interface-technologies/iti-react": "4.2.
|
27
|
-
"@interface-technologies/tsconfig": "4.2.
|
26
|
+
"@interface-technologies/iti-react": "4.2.2",
|
27
|
+
"@interface-technologies/tsconfig": "4.2.2",
|
28
28
|
"@redux-saga/is": "^1.1.2",
|
29
29
|
"@redux-saga/symbols": "^1.1.2",
|
30
30
|
"@testing-library/react-hooks": "^7.0.2",
|
@@ -32,7 +32,7 @@
|
|
32
32
|
"redux-saga-test-plan": "^4.0.4"
|
33
33
|
},
|
34
34
|
"peerDependencies": {
|
35
|
-
"@interface-technologies/iti-react": "^4.2.
|
35
|
+
"@interface-technologies/iti-react": "^4.2.2",
|
36
36
|
"@popperjs/core": "^2.10.2",
|
37
37
|
"bootstrap": "^5.1.2",
|
38
38
|
"react": "^17.0.2"
|