react-native-instant-webview 0.1.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/README.md +170 -0
- package/lib/commonjs/PooledWebView.js +112 -0
- package/lib/commonjs/PooledWebView.js.map +1 -0
- package/lib/commonjs/WebViewManager.js +102 -0
- package/lib/commonjs/WebViewManager.js.map +1 -0
- package/lib/commonjs/WebViewPoolProvider.js +102 -0
- package/lib/commonjs/WebViewPoolProvider.js.map +1 -0
- package/lib/commonjs/WebViewSlot.js +91 -0
- package/lib/commonjs/WebViewSlot.js.map +1 -0
- package/lib/commonjs/constants.js +51 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/index.js +41 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/types.js +6 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/usePooledWebView.js +54 -0
- package/lib/commonjs/usePooledWebView.js.map +1 -0
- package/lib/module/PooledWebView.js +105 -0
- package/lib/module/PooledWebView.js.map +1 -0
- package/lib/module/WebViewManager.js +96 -0
- package/lib/module/WebViewManager.js.map +1 -0
- package/lib/module/WebViewPoolProvider.js +92 -0
- package/lib/module/WebViewPoolProvider.js.map +1 -0
- package/lib/module/WebViewSlot.js +84 -0
- package/lib/module/WebViewSlot.js.map +1 -0
- package/lib/module/constants.js +45 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/usePooledWebView.js +48 -0
- package/lib/module/usePooledWebView.js.map +1 -0
- package/lib/typescript/PooledWebView.d.ts +5 -0
- package/lib/typescript/PooledWebView.d.ts.map +1 -0
- package/lib/typescript/WebViewManager.d.ts +21 -0
- package/lib/typescript/WebViewManager.d.ts.map +1 -0
- package/lib/typescript/WebViewPoolProvider.d.ts +6 -0
- package/lib/typescript/WebViewPoolProvider.d.ts.map +1 -0
- package/lib/typescript/WebViewSlot.d.ts +13 -0
- package/lib/typescript/WebViewSlot.d.ts.map +1 -0
- package/lib/typescript/__mocks__/react-native-webview.d.ts +12 -0
- package/lib/typescript/__mocks__/react-native-webview.d.ts.map +1 -0
- package/lib/typescript/__mocks__/react-native.d.ts +18 -0
- package/lib/typescript/__mocks__/react-native.d.ts.map +1 -0
- package/lib/typescript/constants.d.ts +9 -0
- package/lib/typescript/constants.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +6 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +62 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/lib/typescript/usePooledWebView.d.ts +3 -0
- package/lib/typescript/usePooledWebView.d.ts.map +1 -0
- package/package.json +87 -0
- package/src/PooledWebView.tsx +105 -0
- package/src/WebViewManager.ts +120 -0
- package/src/WebViewPoolProvider.tsx +138 -0
- package/src/WebViewSlot.tsx +107 -0
- package/src/__mocks__/react-native-webview.tsx +16 -0
- package/src/__mocks__/react-native.ts +14 -0
- package/src/constants.ts +46 -0
- package/src/index.tsx +17 -0
- package/src/types.ts +72 -0
- package/src/usePooledWebView.ts +58 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.HIDDEN_STYLE = exports.DEFAULT_POOL_CONFIG = exports.CLEANUP_SCRIPT = exports.BLANK_HTML_SOURCE = void 0;
|
|
7
|
+
const DEFAULT_POOL_CONFIG = exports.DEFAULT_POOL_CONFIG = {
|
|
8
|
+
poolSize: 3,
|
|
9
|
+
cleanupOnReturn: true
|
|
10
|
+
};
|
|
11
|
+
const HIDDEN_STYLE = exports.HIDDEN_STYLE = {
|
|
12
|
+
position: 'absolute',
|
|
13
|
+
width: 1,
|
|
14
|
+
height: 1,
|
|
15
|
+
left: -9999,
|
|
16
|
+
top: -9999,
|
|
17
|
+
opacity: 0
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Blank HTML source used for idle/cleaning WebViews.
|
|
21
|
+
// Using { html } instead of { uri: 'about:blank' } because
|
|
22
|
+
// react-native-webview's native code may route 'about:blank'
|
|
23
|
+
// through loadFileURL: which throws NSInvalidArgumentException.
|
|
24
|
+
const BLANK_HTML_SOURCE = exports.BLANK_HTML_SOURCE = {
|
|
25
|
+
html: ''
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Cleanup script injected into WebView when returning to pool.
|
|
29
|
+
// Resets scroll position, clears timers, and removes all body content.
|
|
30
|
+
// The body.innerHTML = '' is intentional — it clears the WebView DOM
|
|
31
|
+
// as part of the pool cleanup process (no user content involved).
|
|
32
|
+
const CLEANUP_SCRIPT = exports.CLEANUP_SCRIPT = `
|
|
33
|
+
(function() {
|
|
34
|
+
try {
|
|
35
|
+
window.scrollTo(0, 0);
|
|
36
|
+
var highestTimeoutId = setTimeout(function(){}, 0);
|
|
37
|
+
for (var i = 0; i < highestTimeoutId; i++) {
|
|
38
|
+
clearTimeout(i);
|
|
39
|
+
}
|
|
40
|
+
var highestIntervalId = setInterval(function(){}, 0);
|
|
41
|
+
for (var j = 0; j < highestIntervalId; j++) {
|
|
42
|
+
clearInterval(j);
|
|
43
|
+
}
|
|
44
|
+
if (document.body) {
|
|
45
|
+
document.body.innerHTML = '';
|
|
46
|
+
}
|
|
47
|
+
} catch(e) {}
|
|
48
|
+
true;
|
|
49
|
+
})();
|
|
50
|
+
`;
|
|
51
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["DEFAULT_POOL_CONFIG","exports","poolSize","cleanupOnReturn","HIDDEN_STYLE","position","width","height","left","top","opacity","BLANK_HTML_SOURCE","html","CLEANUP_SCRIPT"],"sourceRoot":"../../src","sources":["constants.ts"],"mappings":";;;;;;AAGO,MAAMA,mBAA+B,GAAAC,OAAA,CAAAD,mBAAA,GAAG;EAC7CE,QAAQ,EAAE,CAAC;EACXC,eAAe,EAAE;AACnB,CAAC;AAEM,MAAMC,YAAuB,GAAAH,OAAA,CAAAG,YAAA,GAAG;EACrCC,QAAQ,EAAE,UAAU;EACpBC,KAAK,EAAE,CAAC;EACRC,MAAM,EAAE,CAAC;EACTC,IAAI,EAAE,CAAC,IAAI;EACXC,GAAG,EAAE,CAAC,IAAI;EACVC,OAAO,EAAE;AACX,CAAC;;AAED;AACA;AACA;AACA;AACO,MAAMC,iBAAiB,GAAAV,OAAA,CAAAU,iBAAA,GAAG;EAAEC,IAAI,EAAE;AAAG,CAAU;;AAEtD;AACA;AACA;AACA;AACO,MAAMC,cAAc,GAAAZ,OAAA,CAAAY,cAAA,GAAG;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "PooledWebView", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _PooledWebView.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "WebViewManager", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _WebViewManager.default;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "WebViewPoolProvider", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _WebViewPoolProvider.WebViewPoolProvider;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "usePooledWebView", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _usePooledWebView.usePooledWebView;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "useWebViewPool", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _WebViewPoolProvider.useWebViewPool;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
var _WebViewPoolProvider = require("./WebViewPoolProvider");
|
|
37
|
+
var _PooledWebView = _interopRequireDefault(require("./PooledWebView"));
|
|
38
|
+
var _usePooledWebView = require("./usePooledWebView");
|
|
39
|
+
var _WebViewManager = _interopRequireDefault(require("./WebViewManager"));
|
|
40
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_WebViewPoolProvider","require","_PooledWebView","_interopRequireDefault","_usePooledWebView","_WebViewManager","e","__esModule","default"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,oBAAA,GAAAC,OAAA;AACA,IAAAC,cAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,iBAAA,GAAAH,OAAA;AACA,IAAAI,eAAA,GAAAF,sBAAA,CAAAF,OAAA;AAA6D,SAAAE,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.usePooledWebView = usePooledWebView;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _WebViewPoolProvider = require("./WebViewPoolProvider");
|
|
9
|
+
let hookBorrowerIdCounter = 0;
|
|
10
|
+
function usePooledWebView() {
|
|
11
|
+
const pool = (0, _WebViewPoolProvider.useWebViewPool)();
|
|
12
|
+
const instanceIdRef = (0, _react.useRef)(null);
|
|
13
|
+
const webViewRefRef = (0, _react.useRef)(null);
|
|
14
|
+
const [instanceId, setInstanceId] = (0, _react.useState)(null);
|
|
15
|
+
(0, _react.useEffect)(() => {
|
|
16
|
+
return () => {
|
|
17
|
+
if (instanceIdRef.current) {
|
|
18
|
+
pool.release(instanceIdRef.current);
|
|
19
|
+
instanceIdRef.current = null;
|
|
20
|
+
webViewRefRef.current = null;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}, [pool]);
|
|
24
|
+
const borrow = (0, _react.useCallback)(() => {
|
|
25
|
+
if (instanceIdRef.current) {
|
|
26
|
+
return {
|
|
27
|
+
instanceId: instanceIdRef.current,
|
|
28
|
+
webViewRef: webViewRefRef.current
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const borrowerId = `hook-borrower-${++hookBorrowerIdCounter}`;
|
|
32
|
+
const result = pool.borrow(borrowerId);
|
|
33
|
+
if (!result) return null;
|
|
34
|
+
instanceIdRef.current = result.instanceId;
|
|
35
|
+
webViewRefRef.current = result.webViewRef;
|
|
36
|
+
setInstanceId(result.instanceId);
|
|
37
|
+
return result;
|
|
38
|
+
}, [pool]);
|
|
39
|
+
const release = (0, _react.useCallback)(() => {
|
|
40
|
+
if (instanceIdRef.current) {
|
|
41
|
+
pool.release(instanceIdRef.current);
|
|
42
|
+
instanceIdRef.current = null;
|
|
43
|
+
webViewRefRef.current = null;
|
|
44
|
+
setInstanceId(null);
|
|
45
|
+
}
|
|
46
|
+
}, [pool]);
|
|
47
|
+
return {
|
|
48
|
+
borrow,
|
|
49
|
+
release,
|
|
50
|
+
instanceId,
|
|
51
|
+
webViewRef: webViewRefRef.current
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=usePooledWebView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","require","_WebViewPoolProvider","hookBorrowerIdCounter","usePooledWebView","pool","useWebViewPool","instanceIdRef","useRef","webViewRefRef","instanceId","setInstanceId","useState","useEffect","current","release","borrow","useCallback","webViewRef","borrowerId","result"],"sourceRoot":"../../src","sources":["usePooledWebView.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAGA,IAAAC,oBAAA,GAAAD,OAAA;AAGA,IAAIE,qBAAqB,GAAG,CAAC;AAEtB,SAASC,gBAAgBA,CAAA,EAA2B;EACzD,MAAMC,IAAI,GAAG,IAAAC,mCAAc,EAAC,CAAC;EAC7B,MAAMC,aAAa,GAAG,IAAAC,aAAM,EAAgB,IAAI,CAAC;EACjD,MAAMC,aAAa,GAAG,IAAAD,aAAM,EAAmC,IAAI,CAAC;EACpE,MAAM,CAACE,UAAU,EAAEC,aAAa,CAAC,GAAG,IAAAC,eAAQ,EAAgB,IAAI,CAAC;EAEjE,IAAAC,gBAAS,EAAC,MAAM;IACd,OAAO,MAAM;MACX,IAAIN,aAAa,CAACO,OAAO,EAAE;QACzBT,IAAI,CAACU,OAAO,CAACR,aAAa,CAACO,OAAO,CAAC;QACnCP,aAAa,CAACO,OAAO,GAAG,IAAI;QAC5BL,aAAa,CAACK,OAAO,GAAG,IAAI;MAC9B;IACF,CAAC;EACH,CAAC,EAAE,CAACT,IAAI,CAAC,CAAC;EAEV,MAAMW,MAAM,GAAG,IAAAC,kBAAW,EAAC,MAAM;IAC/B,IAAIV,aAAa,CAACO,OAAO,EAAE;MACzB,OAAO;QACLJ,UAAU,EAAEH,aAAa,CAACO,OAAO;QACjCI,UAAU,EAAET,aAAa,CAACK;MAC5B,CAAC;IACH;IAEA,MAAMK,UAAU,GAAG,iBAAiB,EAAEhB,qBAAqB,EAAE;IAC7D,MAAMiB,MAAM,GAAGf,IAAI,CAACW,MAAM,CAACG,UAAU,CAAC;IACtC,IAAI,CAACC,MAAM,EAAE,OAAO,IAAI;IAExBb,aAAa,CAACO,OAAO,GAAGM,MAAM,CAACV,UAAU;IACzCD,aAAa,CAACK,OAAO,GAAGM,MAAM,CAACF,UAAU;IACzCP,aAAa,CAACS,MAAM,CAACV,UAAU,CAAC;IAChC,OAAOU,MAAM;EACf,CAAC,EAAE,CAACf,IAAI,CAAC,CAAC;EAEV,MAAMU,OAAO,GAAG,IAAAE,kBAAW,EAAC,MAAM;IAChC,IAAIV,aAAa,CAACO,OAAO,EAAE;MACzBT,IAAI,CAACU,OAAO,CAACR,aAAa,CAACO,OAAO,CAAC;MACnCP,aAAa,CAACO,OAAO,GAAG,IAAI;MAC5BL,aAAa,CAACK,OAAO,GAAG,IAAI;MAC5BH,aAAa,CAAC,IAAI,CAAC;IACrB;EACF,CAAC,EAAE,CAACN,IAAI,CAAC,CAAC;EAEV,OAAO;IACLW,MAAM;IACND,OAAO;IACPL,UAAU;IACVQ,UAAU,EAAET,aAAa,CAACK;EAC5B,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import { WebView } from 'react-native-webview';
|
|
5
|
+
import { useWebViewPool } from './WebViewPoolProvider';
|
|
6
|
+
let borrowerIdCounter = 0;
|
|
7
|
+
const PooledWebView = ({
|
|
8
|
+
poolKey,
|
|
9
|
+
containerStyle,
|
|
10
|
+
onPoolExhausted,
|
|
11
|
+
onBorrowed,
|
|
12
|
+
onReturned,
|
|
13
|
+
source,
|
|
14
|
+
...webViewProps
|
|
15
|
+
}) => {
|
|
16
|
+
const pool = useWebViewPool();
|
|
17
|
+
const instanceIdRef = useRef(null);
|
|
18
|
+
const placeholderRef = useRef(null);
|
|
19
|
+
const borrowerIdRef = useRef(poolKey ?? `borrower-${++borrowerIdCounter}`);
|
|
20
|
+
const propsRef = useRef({
|
|
21
|
+
source,
|
|
22
|
+
...webViewProps
|
|
23
|
+
});
|
|
24
|
+
const [borrowed, setBorrowed] = useState(false);
|
|
25
|
+
const [fallback, setFallback] = useState(false);
|
|
26
|
+
|
|
27
|
+
// Keep propsRef in sync without triggering re-renders
|
|
28
|
+
propsRef.current = {
|
|
29
|
+
source,
|
|
30
|
+
...webViewProps
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Borrow on mount
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const result = pool.borrow(borrowerIdRef.current);
|
|
36
|
+
if (!result) {
|
|
37
|
+
setFallback(true);
|
|
38
|
+
onPoolExhausted?.();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
instanceIdRef.current = result.instanceId;
|
|
42
|
+
pool.setInstanceProps(result.instanceId, propsRef.current);
|
|
43
|
+
setBorrowed(true);
|
|
44
|
+
onBorrowed?.(result.instanceId);
|
|
45
|
+
return () => {
|
|
46
|
+
const id = instanceIdRef.current;
|
|
47
|
+
if (id) {
|
|
48
|
+
pool.setInstanceLayout(id, null);
|
|
49
|
+
pool.release(id);
|
|
50
|
+
onReturned?.(id);
|
|
51
|
+
instanceIdRef.current = null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
// Update props when source changes (the primary prop that changes)
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const id = instanceIdRef.current;
|
|
60
|
+
if (!id || !borrowed) return;
|
|
61
|
+
pool.setInstanceProps(id, propsRef.current);
|
|
62
|
+
// Only re-sync when source actually changes
|
|
63
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
64
|
+
}, [source]);
|
|
65
|
+
|
|
66
|
+
// Measure placeholder position
|
|
67
|
+
const handleLayout = useCallback(_event => {
|
|
68
|
+
const id = instanceIdRef.current;
|
|
69
|
+
if (!id || !placeholderRef.current) return;
|
|
70
|
+
placeholderRef.current.measureInWindow((x, y, width, height) => {
|
|
71
|
+
if (width > 0 && height > 0) {
|
|
72
|
+
pool.setInstanceLayout(id, {
|
|
73
|
+
top: y,
|
|
74
|
+
left: x,
|
|
75
|
+
width,
|
|
76
|
+
height
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}, [pool]);
|
|
81
|
+
|
|
82
|
+
// Pool exhausted — fall back to a regular WebView
|
|
83
|
+
if (fallback) {
|
|
84
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
85
|
+
style: [{
|
|
86
|
+
flex: 1
|
|
87
|
+
}, containerStyle]
|
|
88
|
+
}, /*#__PURE__*/React.createElement(WebView, _extends({
|
|
89
|
+
source: source
|
|
90
|
+
}, webViewProps, {
|
|
91
|
+
style: {
|
|
92
|
+
flex: 1
|
|
93
|
+
}
|
|
94
|
+
})));
|
|
95
|
+
}
|
|
96
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
97
|
+
ref: placeholderRef,
|
|
98
|
+
style: [{
|
|
99
|
+
flex: 1
|
|
100
|
+
}, containerStyle],
|
|
101
|
+
onLayout: handleLayout
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
export default /*#__PURE__*/React.memo(PooledWebView);
|
|
105
|
+
//# sourceMappingURL=PooledWebView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useCallback","useEffect","useRef","useState","View","WebView","useWebViewPool","borrowerIdCounter","PooledWebView","poolKey","containerStyle","onPoolExhausted","onBorrowed","onReturned","source","webViewProps","pool","instanceIdRef","placeholderRef","borrowerIdRef","propsRef","borrowed","setBorrowed","fallback","setFallback","current","result","borrow","instanceId","setInstanceProps","id","setInstanceLayout","release","handleLayout","_event","measureInWindow","x","y","width","height","top","left","createElement","style","flex","_extends","ref","onLayout","memo"],"sourceRoot":"../../src","sources":["PooledWebView.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createRef } from 'react';
|
|
2
|
+
import { DEFAULT_POOL_CONFIG } from './constants';
|
|
3
|
+
class WebViewManager {
|
|
4
|
+
static instance = null;
|
|
5
|
+
config = DEFAULT_POOL_CONFIG;
|
|
6
|
+
instances = [];
|
|
7
|
+
listeners = new Set();
|
|
8
|
+
initialized = false;
|
|
9
|
+
constructor() {}
|
|
10
|
+
static getInstance() {
|
|
11
|
+
if (!WebViewManager.instance) {
|
|
12
|
+
WebViewManager.instance = new WebViewManager();
|
|
13
|
+
}
|
|
14
|
+
return WebViewManager.instance;
|
|
15
|
+
}
|
|
16
|
+
static resetInstance() {
|
|
17
|
+
WebViewManager.instance = null;
|
|
18
|
+
}
|
|
19
|
+
initialize(config) {
|
|
20
|
+
if (this.initialized) return;
|
|
21
|
+
this.config = {
|
|
22
|
+
...DEFAULT_POOL_CONFIG,
|
|
23
|
+
...config
|
|
24
|
+
};
|
|
25
|
+
this.instances = [];
|
|
26
|
+
for (let i = 0; i < this.config.poolSize; i++) {
|
|
27
|
+
this.instances.push({
|
|
28
|
+
id: `webview-pool-${i}`,
|
|
29
|
+
status: 'idle',
|
|
30
|
+
webViewRef: /*#__PURE__*/createRef(),
|
|
31
|
+
borrowerId: null,
|
|
32
|
+
createdAt: Date.now(),
|
|
33
|
+
borrowedAt: null
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
this.initialized = true;
|
|
37
|
+
this.notify();
|
|
38
|
+
}
|
|
39
|
+
borrow(borrowerId) {
|
|
40
|
+
const idle = this.instances.find(inst => inst.status === 'idle');
|
|
41
|
+
if (!idle) return null;
|
|
42
|
+
idle.status = 'borrowed';
|
|
43
|
+
idle.borrowerId = borrowerId;
|
|
44
|
+
idle.borrowedAt = Date.now();
|
|
45
|
+
this.notify();
|
|
46
|
+
return {
|
|
47
|
+
instanceId: idle.id,
|
|
48
|
+
webViewRef: idle.webViewRef
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
release(instanceId) {
|
|
52
|
+
const inst = this.instances.find(i => i.id === instanceId);
|
|
53
|
+
if (!inst || inst.status !== 'borrowed') return;
|
|
54
|
+
if (this.config.cleanupOnReturn) {
|
|
55
|
+
inst.status = 'cleaning';
|
|
56
|
+
} else {
|
|
57
|
+
inst.status = 'idle';
|
|
58
|
+
inst.borrowerId = null;
|
|
59
|
+
inst.borrowedAt = null;
|
|
60
|
+
}
|
|
61
|
+
this.notify();
|
|
62
|
+
}
|
|
63
|
+
markIdle(instanceId) {
|
|
64
|
+
const inst = this.instances.find(i => i.id === instanceId);
|
|
65
|
+
if (!inst) return;
|
|
66
|
+
inst.status = 'idle';
|
|
67
|
+
inst.borrowerId = null;
|
|
68
|
+
inst.borrowedAt = null;
|
|
69
|
+
this.notify();
|
|
70
|
+
}
|
|
71
|
+
getState() {
|
|
72
|
+
return {
|
|
73
|
+
instances: [...this.instances],
|
|
74
|
+
availableCount: this.instances.filter(i => i.status === 'idle').length,
|
|
75
|
+
borrowedCount: this.instances.filter(i => i.status === 'borrowed').length,
|
|
76
|
+
initialized: this.initialized
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
getConfig() {
|
|
80
|
+
return {
|
|
81
|
+
...this.config
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
subscribe(listener) {
|
|
85
|
+
this.listeners.add(listener);
|
|
86
|
+
return () => {
|
|
87
|
+
this.listeners.delete(listener);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
notify() {
|
|
91
|
+
const state = this.getState();
|
|
92
|
+
this.listeners.forEach(listener => listener(state));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export default WebViewManager;
|
|
96
|
+
//# sourceMappingURL=WebViewManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["createRef","DEFAULT_POOL_CONFIG","WebViewManager","instance","config","instances","listeners","Set","initialized","constructor","getInstance","resetInstance","initialize","i","poolSize","push","id","status","webViewRef","borrowerId","createdAt","Date","now","borrowedAt","notify","borrow","idle","find","inst","instanceId","release","cleanupOnReturn","markIdle","getState","availableCount","filter","length","borrowedCount","getConfig","subscribe","listener","add","delete","state","forEach"],"sourceRoot":"../../src","sources":["WebViewManager.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import { DEFAULT_POOL_CONFIG } from './constants';
|
|
4
|
+
import WebViewManager from './WebViewManager';
|
|
5
|
+
import WebViewSlot from './WebViewSlot';
|
|
6
|
+
const WebViewPoolContext = /*#__PURE__*/createContext(null);
|
|
7
|
+
export function useWebViewPool() {
|
|
8
|
+
const ctx = useContext(WebViewPoolContext);
|
|
9
|
+
if (!ctx) {
|
|
10
|
+
throw new Error('useWebViewPool must be used within a WebViewPoolProvider');
|
|
11
|
+
}
|
|
12
|
+
return ctx;
|
|
13
|
+
}
|
|
14
|
+
export const WebViewPoolProvider = ({
|
|
15
|
+
config,
|
|
16
|
+
children
|
|
17
|
+
}) => {
|
|
18
|
+
const managerRef = useRef(WebViewManager.getInstance());
|
|
19
|
+
const mergedConfig = useRef({
|
|
20
|
+
...DEFAULT_POOL_CONFIG,
|
|
21
|
+
...config
|
|
22
|
+
}).current;
|
|
23
|
+
const [poolState, setPoolState] = useState(() => {
|
|
24
|
+
const mgr = managerRef.current;
|
|
25
|
+
mgr.initialize(mergedConfig);
|
|
26
|
+
return mgr.getState();
|
|
27
|
+
});
|
|
28
|
+
const layoutsRef = useRef(new Map());
|
|
29
|
+
const propsRef = useRef(new Map());
|
|
30
|
+
const [, forceRender] = useState(0);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const mgr = managerRef.current;
|
|
33
|
+
const unsub = mgr.subscribe(state => {
|
|
34
|
+
setPoolState(state);
|
|
35
|
+
});
|
|
36
|
+
return unsub;
|
|
37
|
+
}, []);
|
|
38
|
+
const borrow = useCallback(borrowerId => {
|
|
39
|
+
return managerRef.current.borrow(borrowerId);
|
|
40
|
+
}, []);
|
|
41
|
+
const release = useCallback(instanceId => {
|
|
42
|
+
layoutsRef.current.delete(instanceId);
|
|
43
|
+
propsRef.current.delete(instanceId);
|
|
44
|
+
managerRef.current.release(instanceId);
|
|
45
|
+
}, []);
|
|
46
|
+
const setInstanceLayout = useCallback((instanceId, layout) => {
|
|
47
|
+
layoutsRef.current.set(instanceId, layout);
|
|
48
|
+
forceRender(c => c + 1);
|
|
49
|
+
}, []);
|
|
50
|
+
const setInstanceProps = useCallback((instanceId, props) => {
|
|
51
|
+
propsRef.current.set(instanceId, props);
|
|
52
|
+
// No forceRender here — the slot reads from propsRef on next render
|
|
53
|
+
// triggered by the Manager's state change (borrow/release).
|
|
54
|
+
}, []);
|
|
55
|
+
const getInstanceLayout = useCallback(instanceId => {
|
|
56
|
+
return layoutsRef.current.get(instanceId) ?? null;
|
|
57
|
+
}, []);
|
|
58
|
+
const getInstanceProps = useCallback(instanceId => {
|
|
59
|
+
return propsRef.current.get(instanceId);
|
|
60
|
+
}, []);
|
|
61
|
+
const handleCleanupComplete = useCallback(instanceId => {
|
|
62
|
+
managerRef.current.markIdle(instanceId);
|
|
63
|
+
}, []);
|
|
64
|
+
const contextValue = {
|
|
65
|
+
state: poolState,
|
|
66
|
+
borrow,
|
|
67
|
+
release,
|
|
68
|
+
setInstanceLayout,
|
|
69
|
+
setInstanceProps,
|
|
70
|
+
getInstanceLayout,
|
|
71
|
+
getInstanceProps
|
|
72
|
+
};
|
|
73
|
+
return /*#__PURE__*/React.createElement(WebViewPoolContext.Provider, {
|
|
74
|
+
value: contextValue
|
|
75
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
76
|
+
style: styles.container
|
|
77
|
+
}, children, poolState.instances.map(instance => /*#__PURE__*/React.createElement(WebViewSlot, {
|
|
78
|
+
key: instance.id,
|
|
79
|
+
instance: instance,
|
|
80
|
+
layout: layoutsRef.current.get(instance.id) ?? null,
|
|
81
|
+
instanceProps: propsRef.current.get(instance.id),
|
|
82
|
+
config: mergedConfig,
|
|
83
|
+
onCleanupComplete: handleCleanupComplete
|
|
84
|
+
}))));
|
|
85
|
+
};
|
|
86
|
+
const styles = StyleSheet.create({
|
|
87
|
+
container: {
|
|
88
|
+
flex: 1
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
export default WebViewPoolProvider;
|
|
92
|
+
//# sourceMappingURL=WebViewPoolProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","createContext","useCallback","useContext","useEffect","useRef","useState","View","StyleSheet","DEFAULT_POOL_CONFIG","WebViewManager","WebViewSlot","WebViewPoolContext","useWebViewPool","ctx","Error","WebViewPoolProvider","config","children","managerRef","getInstance","mergedConfig","current","poolState","setPoolState","mgr","initialize","getState","layoutsRef","Map","propsRef","forceRender","unsub","subscribe","state","borrow","borrowerId","release","instanceId","delete","setInstanceLayout","layout","set","c","setInstanceProps","props","getInstanceLayout","get","getInstanceProps","handleCleanupComplete","markIdle","contextValue","createElement","Provider","value","style","styles","container","instances","map","instance","key","id","instanceProps","onCleanupComplete","create","flex"],"sourceRoot":"../../src","sources":["WebViewPoolProvider.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import { WebView } from 'react-native-webview';
|
|
5
|
+
import { BLANK_HTML_SOURCE, CLEANUP_SCRIPT, HIDDEN_STYLE } from './constants';
|
|
6
|
+
const WebViewSlot = ({
|
|
7
|
+
instance,
|
|
8
|
+
layout,
|
|
9
|
+
instanceProps,
|
|
10
|
+
config,
|
|
11
|
+
onCleanupComplete
|
|
12
|
+
}) => {
|
|
13
|
+
const isVisible = instance.status === 'borrowed' && layout != null;
|
|
14
|
+
const prevStatusRef = useRef(instance.status);
|
|
15
|
+
|
|
16
|
+
// Track whether this slot has ever had a WebView rendered.
|
|
17
|
+
// On first borrow the WebView is created with a valid user source,
|
|
18
|
+
// avoiding the Fabric crash where didMoveToWindow fires before
|
|
19
|
+
// the source prop is applied (causing loadFileURL: with nil URL).
|
|
20
|
+
// After the first borrow, the WebView stays alive through
|
|
21
|
+
// cleaning → idle cycles.
|
|
22
|
+
const [hasWebView, setHasWebView] = useState(false);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (instance.status === 'borrowed' && !hasWebView) {
|
|
25
|
+
setHasWebView(true);
|
|
26
|
+
}
|
|
27
|
+
}, [instance.status, hasWebView]);
|
|
28
|
+
|
|
29
|
+
// When entering cleaning state, inject cleanup script then mark idle
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (prevStatusRef.current !== 'cleaning' && instance.status === 'cleaning') {
|
|
32
|
+
const ref = instance.webViewRef.current;
|
|
33
|
+
if (ref) {
|
|
34
|
+
const script = config.customCleanupScript ?? CLEANUP_SCRIPT;
|
|
35
|
+
ref.injectJavaScript(script);
|
|
36
|
+
}
|
|
37
|
+
const timer = setTimeout(() => {
|
|
38
|
+
onCleanupComplete(instance.id);
|
|
39
|
+
}, 100);
|
|
40
|
+
return () => clearTimeout(timer);
|
|
41
|
+
}
|
|
42
|
+
prevStatusRef.current = instance.status;
|
|
43
|
+
}, [instance.status, instance.id, instance.webViewRef, config.customCleanupScript, onCleanupComplete]);
|
|
44
|
+
const containerStyle = useMemo(() => {
|
|
45
|
+
if (!isVisible || !layout) {
|
|
46
|
+
return HIDDEN_STYLE;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
position: 'absolute',
|
|
50
|
+
top: layout.top,
|
|
51
|
+
left: layout.left,
|
|
52
|
+
width: layout.width,
|
|
53
|
+
height: layout.height
|
|
54
|
+
};
|
|
55
|
+
}, [isVisible, layout]);
|
|
56
|
+
const handleNavigationStateChange = useCallback(navState => {
|
|
57
|
+
instanceProps?.onNavigationStateChange?.(navState);
|
|
58
|
+
}, [instanceProps]);
|
|
59
|
+
const source = useMemo(() => {
|
|
60
|
+
if (instance.status === 'borrowed' && instanceProps?.source) {
|
|
61
|
+
return instanceProps.source;
|
|
62
|
+
}
|
|
63
|
+
return BLANK_HTML_SOURCE;
|
|
64
|
+
}, [instance.status, instanceProps?.source]);
|
|
65
|
+
|
|
66
|
+
// Don't render WebView until the first borrow.
|
|
67
|
+
// This avoids the Fabric crash where didMoveToWindow → visitSource
|
|
68
|
+
// fires before _source prop is applied on the native side.
|
|
69
|
+
const shouldRenderWebView = hasWebView;
|
|
70
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
71
|
+
style: containerStyle,
|
|
72
|
+
pointerEvents: isVisible ? 'auto' : 'none'
|
|
73
|
+
}, shouldRenderWebView && /*#__PURE__*/React.createElement(WebView, _extends({
|
|
74
|
+
ref: instance.webViewRef
|
|
75
|
+
}, instance.status === 'borrowed' ? instanceProps : undefined, {
|
|
76
|
+
source: source,
|
|
77
|
+
onNavigationStateChange: handleNavigationStateChange,
|
|
78
|
+
style: {
|
|
79
|
+
flex: 1
|
|
80
|
+
}
|
|
81
|
+
}, config.defaultWebViewProps || {})));
|
|
82
|
+
};
|
|
83
|
+
export default /*#__PURE__*/React.memo(WebViewSlot);
|
|
84
|
+
//# sourceMappingURL=WebViewSlot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","View","WebView","BLANK_HTML_SOURCE","CLEANUP_SCRIPT","HIDDEN_STYLE","WebViewSlot","instance","layout","instanceProps","config","onCleanupComplete","isVisible","status","prevStatusRef","hasWebView","setHasWebView","current","ref","webViewRef","script","customCleanupScript","injectJavaScript","timer","setTimeout","id","clearTimeout","containerStyle","position","top","left","width","height","handleNavigationStateChange","navState","onNavigationStateChange","source","shouldRenderWebView","createElement","style","pointerEvents","_extends","undefined","flex","defaultWebViewProps","memo"],"sourceRoot":"../../src","sources":["WebViewSlot.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const DEFAULT_POOL_CONFIG = {
|
|
2
|
+
poolSize: 3,
|
|
3
|
+
cleanupOnReturn: true
|
|
4
|
+
};
|
|
5
|
+
export const HIDDEN_STYLE = {
|
|
6
|
+
position: 'absolute',
|
|
7
|
+
width: 1,
|
|
8
|
+
height: 1,
|
|
9
|
+
left: -9999,
|
|
10
|
+
top: -9999,
|
|
11
|
+
opacity: 0
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Blank HTML source used for idle/cleaning WebViews.
|
|
15
|
+
// Using { html } instead of { uri: 'about:blank' } because
|
|
16
|
+
// react-native-webview's native code may route 'about:blank'
|
|
17
|
+
// through loadFileURL: which throws NSInvalidArgumentException.
|
|
18
|
+
export const BLANK_HTML_SOURCE = {
|
|
19
|
+
html: ''
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Cleanup script injected into WebView when returning to pool.
|
|
23
|
+
// Resets scroll position, clears timers, and removes all body content.
|
|
24
|
+
// The body.innerHTML = '' is intentional — it clears the WebView DOM
|
|
25
|
+
// as part of the pool cleanup process (no user content involved).
|
|
26
|
+
export const CLEANUP_SCRIPT = `
|
|
27
|
+
(function() {
|
|
28
|
+
try {
|
|
29
|
+
window.scrollTo(0, 0);
|
|
30
|
+
var highestTimeoutId = setTimeout(function(){}, 0);
|
|
31
|
+
for (var i = 0; i < highestTimeoutId; i++) {
|
|
32
|
+
clearTimeout(i);
|
|
33
|
+
}
|
|
34
|
+
var highestIntervalId = setInterval(function(){}, 0);
|
|
35
|
+
for (var j = 0; j < highestIntervalId; j++) {
|
|
36
|
+
clearInterval(j);
|
|
37
|
+
}
|
|
38
|
+
if (document.body) {
|
|
39
|
+
document.body.innerHTML = '';
|
|
40
|
+
}
|
|
41
|
+
} catch(e) {}
|
|
42
|
+
true;
|
|
43
|
+
})();
|
|
44
|
+
`;
|
|
45
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["DEFAULT_POOL_CONFIG","poolSize","cleanupOnReturn","HIDDEN_STYLE","position","width","height","left","top","opacity","BLANK_HTML_SOURCE","html","CLEANUP_SCRIPT"],"sourceRoot":"../../src","sources":["constants.ts"],"mappings":"AAGA,OAAO,MAAMA,mBAA+B,GAAG;EAC7CC,QAAQ,EAAE,CAAC;EACXC,eAAe,EAAE;AACnB,CAAC;AAED,OAAO,MAAMC,YAAuB,GAAG;EACrCC,QAAQ,EAAE,UAAU;EACpBC,KAAK,EAAE,CAAC;EACRC,MAAM,EAAE,CAAC;EACTC,IAAI,EAAE,CAAC,IAAI;EACXC,GAAG,EAAE,CAAC,IAAI;EACVC,OAAO,EAAE;AACX,CAAC;;AAED;AACA;AACA;AACA;AACA,OAAO,MAAMC,iBAAiB,GAAG;EAAEC,IAAI,EAAE;AAAG,CAAU;;AAEtD;AACA;AACA;AACA;AACA,OAAO,MAAMC,cAAc,GAAG;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { WebViewPoolProvider, useWebViewPool } from './WebViewPoolProvider';
|
|
2
|
+
export { default as PooledWebView } from './PooledWebView';
|
|
3
|
+
export { usePooledWebView } from './usePooledWebView';
|
|
4
|
+
export { default as WebViewManager } from './WebViewManager';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["WebViewPoolProvider","useWebViewPool","default","PooledWebView","usePooledWebView","WebViewManager"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,mBAAmB,EAAEC,cAAc,QAAQ,uBAAuB;AAC3E,SAASC,OAAO,IAAIC,aAAa,QAAQ,iBAAiB;AAC1D,SAASC,gBAAgB,QAAQ,oBAAoB;AACrD,SAASF,OAAO,IAAIG,cAAc,QAAQ,kBAAkB","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
|