@jsenv/core 27.6.1 → 27.8.1
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/js/autoreload.js +3 -6
- package/dist/js/html_supervisor_installer.js +36 -32
- package/dist/js/html_supervisor_setup.js +10 -2
- package/dist/js/server_events_client.js +249 -216
- package/dist/js/wrapper.mjs +4233 -0
- package/dist/main.js +21266 -21628
- package/package.json +3 -3
- package/src/build/build.js +19 -18
- package/src/dev/start_dev_server.js +7 -11
- package/src/execute/execute.js +2 -2
- package/src/execute/runtimes/browsers/chromium.js +1 -1
- package/src/execute/runtimes/browsers/firefox.js +1 -1
- package/src/execute/runtimes/browsers/webkit.js +1 -1
- package/src/omega/kitchen.js +9 -14
- package/src/omega/omega_server.js +13 -2
- package/src/omega/server/file_service.js +13 -29
- package/src/plugins/autoreload/client/autoreload.js +3 -4
- package/src/plugins/autoreload/jsenv_plugin_autoreload.js +0 -4
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -1
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +1 -1
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +1 -1
- package/src/plugins/bundling/jsenv_plugin_bundling.js +1 -3
- package/src/plugins/cache_control/jsenv_plugin_cache_control.js +2 -5
- package/src/plugins/commonjs_globals/jsenv_plugin_commonjs_globals.js +2 -2
- package/src/plugins/file_urls/jsenv_plugin_file_urls.js +4 -8
- package/src/plugins/html_supervisor/client/error_formatter.js +43 -37
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +1 -4
- package/src/plugins/html_supervisor/client/html_supervisor_setup.js +10 -2
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +4 -5
- package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +2 -2
- package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +18 -24
- package/src/plugins/importmap/jsenv_plugin_importmap.js +1 -1
- package/src/plugins/minification/jsenv_plugin_minification.js +1 -3
- package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +9 -7
- package/src/plugins/plugin_controller.js +17 -6
- package/src/plugins/plugins.js +0 -2
- package/src/plugins/server_events/client/connection_manager.js +165 -0
- package/src/plugins/server_events/client/event_source_connection.js +50 -256
- package/src/plugins/server_events/client/events_manager.js +75 -0
- package/src/plugins/server_events/client/server_events_client.js +12 -11
- package/src/plugins/server_events/client/web_socket_connection.js +81 -0
- package/src/plugins/server_events/server_events_dispatcher.js +70 -54
- package/src/plugins/toolbar/jsenv_plugin_toolbar.js +1 -3
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +1 -1
- package/src/plugins/url_analysis/html/html_urls.js +2 -2
- package/src/test/execute_plan.js +2 -2
- package/src/test/execute_test_plan.js +1 -1
|
@@ -9,11 +9,12 @@ window.__html_supervisor__ = {
|
|
|
9
9
|
window.__html_supervisor__.scriptsToExecute.push(scriptToExecute)
|
|
10
10
|
},
|
|
11
11
|
superviseScript: ({ src, isInline, crossorigin, integrity }) => {
|
|
12
|
+
const { currentScript } = document
|
|
12
13
|
window.__html_supervisor__.addScriptToExecute({
|
|
13
14
|
src,
|
|
14
15
|
type: "js_classic",
|
|
15
16
|
isInline,
|
|
16
|
-
currentScript
|
|
17
|
+
currentScript,
|
|
17
18
|
execute: (url) => {
|
|
18
19
|
return new Promise((resolve, reject) => {
|
|
19
20
|
const script = document.createElement("script")
|
|
@@ -50,7 +51,14 @@ window.__html_supervisor__ = {
|
|
|
50
51
|
resolve()
|
|
51
52
|
}
|
|
52
53
|
})
|
|
53
|
-
|
|
54
|
+
if (currentScript) {
|
|
55
|
+
currentScript.parentNode.insertBefore(
|
|
56
|
+
script,
|
|
57
|
+
currentScript.nextSibling,
|
|
58
|
+
)
|
|
59
|
+
} else {
|
|
60
|
+
document.body.appendChild(script)
|
|
61
|
+
}
|
|
54
62
|
})
|
|
55
63
|
},
|
|
56
64
|
})
|
|
@@ -43,10 +43,7 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
43
43
|
|
|
44
44
|
return {
|
|
45
45
|
name: "jsenv:html_supervisor",
|
|
46
|
-
appliesDuring:
|
|
47
|
-
dev: true,
|
|
48
|
-
test: true,
|
|
49
|
-
},
|
|
46
|
+
appliesDuring: "dev",
|
|
50
47
|
serve: async (request, context) => {
|
|
51
48
|
if (request.ressource.startsWith("/__get_code_frame__/")) {
|
|
52
49
|
const { pathname, searchParams } = new URL(request.url)
|
|
@@ -132,7 +129,9 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
132
129
|
code: causeInfo.code,
|
|
133
130
|
message: causeInfo.message,
|
|
134
131
|
reason: causeInfo.reason,
|
|
135
|
-
stack:
|
|
132
|
+
stack: errorBaseUrl
|
|
133
|
+
? `stack mocked for snapshot`
|
|
134
|
+
: causeInfo.stack,
|
|
136
135
|
codeFrame: causeInfo.traceMessage,
|
|
137
136
|
}
|
|
138
137
|
: null,
|
|
@@ -16,7 +16,7 @@ export const jsenvPluginImportMetaHot = () => {
|
|
|
16
16
|
transformUrlContent: {
|
|
17
17
|
html: (htmlUrlInfo, context) => {
|
|
18
18
|
// during build we don't really care to parse html hot dependencies
|
|
19
|
-
if (context.
|
|
19
|
+
if (context.scenarios.build) {
|
|
20
20
|
return
|
|
21
21
|
}
|
|
22
22
|
const htmlAst = parseHtmlString(htmlUrlInfo.content)
|
|
@@ -58,7 +58,7 @@ export const jsenvPluginImportMetaHot = () => {
|
|
|
58
58
|
if (importMetaHotPaths.length === 0) {
|
|
59
59
|
return null
|
|
60
60
|
}
|
|
61
|
-
if (context.
|
|
61
|
+
if (context.scenarios.build) {
|
|
62
62
|
return removeImportMetaHots(urlInfo, importMetaHotPaths)
|
|
63
63
|
}
|
|
64
64
|
return injectImportMetaHot(urlInfo, context, importMetaHotClientFileUrl)
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Source code can contain the following
|
|
3
3
|
* - import.meta.dev
|
|
4
|
-
* - import.meta.test
|
|
5
4
|
* - import.meta.build
|
|
6
5
|
* They are either:
|
|
7
6
|
* - replaced by true: When scenario matches (import.meta.dev and it's the dev server)
|
|
8
|
-
* - left as is to be evaluated to undefined (import.meta.
|
|
7
|
+
* - left as is to be evaluated to undefined (import.meta.build but it's the dev server)
|
|
9
8
|
* - replaced by undefined (import.meta.dev but it's build; the goal is to ensure it's tree-shaked)
|
|
10
9
|
*/
|
|
11
10
|
|
|
@@ -17,7 +16,7 @@ export const jsenvPluginImportMetaScenarios = () => {
|
|
|
17
16
|
name: "jsenv:import_meta_scenario",
|
|
18
17
|
appliesDuring: "*",
|
|
19
18
|
transformUrlContent: {
|
|
20
|
-
js_module: async (urlInfo,
|
|
19
|
+
js_module: async (urlInfo, context) => {
|
|
21
20
|
if (
|
|
22
21
|
!urlInfo.content.includes("import.meta.dev") &&
|
|
23
22
|
!urlInfo.content.includes("import.meta.test") &&
|
|
@@ -34,34 +33,30 @@ export const jsenvPluginImportMetaScenarios = () => {
|
|
|
34
33
|
const replace = (path, value) => {
|
|
35
34
|
replacements.push({ path, value })
|
|
36
35
|
}
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
replace(path, "true")
|
|
40
|
-
})
|
|
41
|
-
} else if (scenario === "test") {
|
|
42
|
-
// test is also considered a dev environment
|
|
43
|
-
// just like the dev server can be used to debug test files
|
|
44
|
-
// without this people would have to write
|
|
45
|
-
// if (import.meta.dev || import.meta.test) or if (!import.meta.build)
|
|
46
|
-
dev.forEach((path) => {
|
|
47
|
-
replace(path, "true")
|
|
48
|
-
})
|
|
49
|
-
test.forEach((path) => {
|
|
50
|
-
replace(path, "true")
|
|
51
|
-
})
|
|
52
|
-
} else if (scenario === "build") {
|
|
53
|
-
// replacing by undefined might not be required
|
|
54
|
-
// as I suppose rollup would consider them as undefined
|
|
55
|
-
// but let's make it explicit to ensure code is properly tree-shaked
|
|
36
|
+
if (context.scenarios.build) {
|
|
37
|
+
// during build ensure replacement for tree-shaking
|
|
56
38
|
dev.forEach((path) => {
|
|
57
39
|
replace(path, "undefined")
|
|
58
40
|
})
|
|
59
41
|
test.forEach((path) => {
|
|
60
|
-
replace(path, "undefined")
|
|
42
|
+
replace(path, context.scenarios.test ? "true" : "undefined")
|
|
61
43
|
})
|
|
62
44
|
build.forEach((path) => {
|
|
63
45
|
replace(path, "true")
|
|
64
46
|
})
|
|
47
|
+
} else {
|
|
48
|
+
// during dev we can let "import.meta.build" untouched
|
|
49
|
+
// it will be evaluated to undefined.
|
|
50
|
+
// Moreover it can be surprising to see some "undefined"
|
|
51
|
+
// when source file contains "import.meta.build"
|
|
52
|
+
dev.forEach((path) => {
|
|
53
|
+
replace(path, "true")
|
|
54
|
+
})
|
|
55
|
+
if (context.scenarios.test) {
|
|
56
|
+
test.forEach((path) => {
|
|
57
|
+
replace(path, "true")
|
|
58
|
+
})
|
|
59
|
+
}
|
|
65
60
|
}
|
|
66
61
|
const magicSource = createMagicSource(urlInfo.content)
|
|
67
62
|
replacements.forEach(({ path, value }) => {
|
|
@@ -106,7 +101,6 @@ const babelPluginMetadataImportMetaScenarios = () => {
|
|
|
106
101
|
})
|
|
107
102
|
state.file.metadata.importMetaScenarios = {
|
|
108
103
|
dev: importMetas.dev,
|
|
109
|
-
test: importMetas.test,
|
|
110
104
|
build: importMetas.build,
|
|
111
105
|
}
|
|
112
106
|
},
|
|
@@ -202,7 +202,7 @@ export const jsenvPluginImportmap = () => {
|
|
|
202
202
|
// by "formatReferencedUrl" making the importmap presence useless.
|
|
203
203
|
// In dev/test we keep importmap into the HTML to see it even if useless
|
|
204
204
|
// Duing build we get rid of it
|
|
205
|
-
if (context.
|
|
205
|
+
if (context.scenarios.build) {
|
|
206
206
|
removeHtmlNode(importmap)
|
|
207
207
|
}
|
|
208
208
|
return {
|
|
@@ -27,8 +27,10 @@ export const jsenvPluginNodeEsmResolution = ({
|
|
|
27
27
|
return {
|
|
28
28
|
name: "jsenv:node_esm_resolution",
|
|
29
29
|
appliesDuring: "*",
|
|
30
|
-
init: (
|
|
31
|
-
const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes(
|
|
30
|
+
init: (context) => {
|
|
31
|
+
const nodeRuntimeEnabled = Object.keys(context.runtimeCompat).includes(
|
|
32
|
+
"node",
|
|
33
|
+
)
|
|
32
34
|
// https://nodejs.org/api/esm.html#resolver-algorithm-specification
|
|
33
35
|
packageConditions = packageConditions || [
|
|
34
36
|
...readCustomConditionsFromProcessArgs(),
|
|
@@ -57,19 +59,19 @@ export const jsenvPluginNodeEsmResolution = ({
|
|
|
57
59
|
return packageJson
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
if (
|
|
62
|
+
if (context.scenarios.dev) {
|
|
61
63
|
const onFileChange = () => {
|
|
62
64
|
packageScopesCache.clear()
|
|
63
65
|
packageJsonsCache.clear()
|
|
64
|
-
urlGraph.urlInfoMap.forEach((urlInfo) => {
|
|
66
|
+
context.urlGraph.urlInfoMap.forEach((urlInfo) => {
|
|
65
67
|
if (urlInfo.dependsOnPackageJson) {
|
|
66
|
-
urlGraph.considerModified(urlInfo)
|
|
68
|
+
context.urlGraph.considerModified(urlInfo)
|
|
67
69
|
}
|
|
68
70
|
})
|
|
69
71
|
}
|
|
70
72
|
filesInvalidatingCache.forEach((file) => {
|
|
71
73
|
const unregister = registerFileLifecycle(
|
|
72
|
-
new URL(file, rootDirectoryUrl),
|
|
74
|
+
new URL(file, context.rootDirectoryUrl),
|
|
73
75
|
{
|
|
74
76
|
added: () => {
|
|
75
77
|
onFileChange()
|
|
@@ -131,7 +133,7 @@ export const jsenvPluginNodeEsmResolution = ({
|
|
|
131
133
|
return null
|
|
132
134
|
},
|
|
133
135
|
transformUrlSearchParams: (reference, context) => {
|
|
134
|
-
if (context.
|
|
136
|
+
if (context.scenarios.build) {
|
|
135
137
|
return null
|
|
136
138
|
}
|
|
137
139
|
if (!reference.url.startsWith("file:")) {
|
|
@@ -17,8 +17,8 @@ const HOOK_NAMES = [
|
|
|
17
17
|
"destroy",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
|
-
export const createPluginController = ({ plugins,
|
|
21
|
-
const flatPlugins = flattenAndFilterPlugins(plugins, {
|
|
20
|
+
export const createPluginController = ({ plugins, scenarios }) => {
|
|
21
|
+
const flatPlugins = flattenAndFilterPlugins(plugins, { scenarios })
|
|
22
22
|
// precompute a list of hooks per hookName for one major reason:
|
|
23
23
|
// - When debugging, there is less iteration
|
|
24
24
|
// also it should increase perf as there is less work to do
|
|
@@ -187,7 +187,7 @@ export const createPluginController = ({ plugins, scenario }) => {
|
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
const flattenAndFilterPlugins = (plugins, {
|
|
190
|
+
const flattenAndFilterPlugins = (plugins, { scenarios }) => {
|
|
191
191
|
const flatPlugins = []
|
|
192
192
|
const visitPluginEntry = (pluginEntry) => {
|
|
193
193
|
if (Array.isArray(pluginEntry)) {
|
|
@@ -208,13 +208,14 @@ const flattenAndFilterPlugins = (plugins, { scenario }) => {
|
|
|
208
208
|
return
|
|
209
209
|
}
|
|
210
210
|
if (typeof appliesDuring === "string") {
|
|
211
|
-
if (!["dev", "
|
|
211
|
+
if (!["dev", "test", "build"].includes(appliesDuring)) {
|
|
212
212
|
throw new Error(
|
|
213
213
|
`"appliesDuring" must be "dev", "test" or "build", got ${appliesDuring}`,
|
|
214
214
|
)
|
|
215
215
|
}
|
|
216
|
-
if (appliesDuring
|
|
216
|
+
if (scenarios[appliesDuring]) {
|
|
217
217
|
flatPlugins.push(pluginEntry)
|
|
218
|
+
return
|
|
218
219
|
}
|
|
219
220
|
return
|
|
220
221
|
}
|
|
@@ -223,7 +224,17 @@ const flattenAndFilterPlugins = (plugins, { scenario }) => {
|
|
|
223
224
|
`"appliesDuring" must be an object or a string, got ${appliesDuring}`,
|
|
224
225
|
)
|
|
225
226
|
}
|
|
226
|
-
|
|
227
|
+
let applies
|
|
228
|
+
for (const key of Object.keys(appliesDuring)) {
|
|
229
|
+
if (!appliesDuring[key] && scenarios[key]) {
|
|
230
|
+
applies = false
|
|
231
|
+
break
|
|
232
|
+
}
|
|
233
|
+
if (appliesDuring[key] && scenarios[key]) {
|
|
234
|
+
applies = true
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (applies) {
|
|
227
238
|
flatPlugins.push(pluginEntry)
|
|
228
239
|
return
|
|
229
240
|
}
|
package/src/plugins/plugins.js
CHANGED
|
@@ -24,7 +24,6 @@ import { jsenvPluginExplorer } from "./explorer/jsenv_plugin_explorer.js"
|
|
|
24
24
|
|
|
25
25
|
export const getCorePlugins = ({
|
|
26
26
|
rootDirectoryUrl,
|
|
27
|
-
scenario,
|
|
28
27
|
runtimeCompat,
|
|
29
28
|
|
|
30
29
|
urlAnalysis = {},
|
|
@@ -84,7 +83,6 @@ export const getCorePlugins = ({
|
|
|
84
83
|
? [
|
|
85
84
|
jsenvPluginAutoreload({
|
|
86
85
|
...clientAutoreload,
|
|
87
|
-
scenario,
|
|
88
86
|
clientFileChangeCallbackList,
|
|
89
87
|
clientFilesPruneCallbackList,
|
|
90
88
|
}),
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const READY_STATES = {
|
|
2
|
+
CONNECTING: "connecting",
|
|
3
|
+
OPEN: "open",
|
|
4
|
+
CLOSING: "closing",
|
|
5
|
+
CLOSED: "closed",
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const createConnectionManager = (
|
|
9
|
+
attemptConnection,
|
|
10
|
+
{ retry, retryAfter, retryMaxAttempt, retryAllocatedMs },
|
|
11
|
+
) => {
|
|
12
|
+
const readyState = {
|
|
13
|
+
value: READY_STATES.CLOSED,
|
|
14
|
+
goTo: (value) => {
|
|
15
|
+
if (value === readyState.value) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
readyState.value = value
|
|
19
|
+
readyState.onchange()
|
|
20
|
+
},
|
|
21
|
+
onchange: () => {},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let _disconnect = () => {}
|
|
25
|
+
const connect = () => {
|
|
26
|
+
if (
|
|
27
|
+
readyState.value === READY_STATES.CONNECTING ||
|
|
28
|
+
readyState.value === READY_STATES.OPEN
|
|
29
|
+
) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let retryCount = 0
|
|
34
|
+
let msSpent = 0
|
|
35
|
+
const attempt = () => {
|
|
36
|
+
readyState.goTo(READY_STATES.CONNECTING)
|
|
37
|
+
_disconnect = attemptConnection({
|
|
38
|
+
onClosed: () => {
|
|
39
|
+
if (!retry) {
|
|
40
|
+
readyState.goTo(READY_STATES.CLOSED)
|
|
41
|
+
console.info(`[jsenv] failed to connect to server`)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
if (retryCount > retryMaxAttempt) {
|
|
45
|
+
readyState.goTo(READY_STATES.CLOSED)
|
|
46
|
+
console.info(
|
|
47
|
+
`[jsenv] could not connect to server after ${retryMaxAttempt} attempt`,
|
|
48
|
+
)
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if (retryAllocatedMs && msSpent > retryAllocatedMs) {
|
|
52
|
+
readyState.goTo(READY_STATES.CLOSED)
|
|
53
|
+
console.info(
|
|
54
|
+
`[jsenv] could not connect to server in less than ${retryAllocatedMs}ms`,
|
|
55
|
+
)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// if closed while open -> connection lost
|
|
60
|
+
// otherwise it's the attempt to connect for the first time
|
|
61
|
+
// or to reconnect
|
|
62
|
+
if (readyState.value === READY_STATES.OPEN) {
|
|
63
|
+
console.info(`[jsenv] server connection lost; retrying to connect`)
|
|
64
|
+
}
|
|
65
|
+
retryCount++
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
msSpent += retryAfter
|
|
68
|
+
attempt()
|
|
69
|
+
}, retryAfter)
|
|
70
|
+
},
|
|
71
|
+
onOpen: () => {
|
|
72
|
+
readyState.goTo(READY_STATES.OPEN)
|
|
73
|
+
// console.info(`[jsenv] connected to server`)
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
attempt()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const disconnect = () => {
|
|
81
|
+
if (
|
|
82
|
+
readyState.value !== READY_STATES.CONNECTING &&
|
|
83
|
+
readyState.value !== READY_STATES.OPEN
|
|
84
|
+
) {
|
|
85
|
+
console.warn(
|
|
86
|
+
`disconnect() ignored because connection is ${readyState.value}`,
|
|
87
|
+
)
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
return _disconnect()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const removePageUnloadListener = listenPageUnload(() => {
|
|
94
|
+
if (
|
|
95
|
+
readyState.value === READY_STATES.CONNECTING ||
|
|
96
|
+
readyState.value === READY_STATES.OPEN
|
|
97
|
+
) {
|
|
98
|
+
_disconnect()
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
readyState,
|
|
104
|
+
connect,
|
|
105
|
+
disconnect,
|
|
106
|
+
destroy: () => {
|
|
107
|
+
removePageUnloadListener()
|
|
108
|
+
disconnect()
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// const listenPageMightFreeze = (callback) => {
|
|
114
|
+
// const removePageHideListener = listenEvent(window, "pagehide", (pageHideEvent) => {
|
|
115
|
+
// if (pageHideEvent.persisted === true) {
|
|
116
|
+
// callback(pageHideEvent)
|
|
117
|
+
// }
|
|
118
|
+
// })
|
|
119
|
+
// return removePageHideListener
|
|
120
|
+
// }
|
|
121
|
+
|
|
122
|
+
// const listenPageFreeze = (callback) => {
|
|
123
|
+
// const removeFreezeListener = listenEvent(document, "freeze", (freezeEvent) => {
|
|
124
|
+
// callback(freezeEvent)
|
|
125
|
+
// })
|
|
126
|
+
// return removeFreezeListener
|
|
127
|
+
// }
|
|
128
|
+
|
|
129
|
+
// const listenPageIsRestored = (callback) => {
|
|
130
|
+
// const removeResumeListener = listenEvent(document, "resume", (resumeEvent) => {
|
|
131
|
+
// removePageshowListener()
|
|
132
|
+
// callback(resumeEvent)
|
|
133
|
+
// })
|
|
134
|
+
// const removePageshowListener = listenEvent(window, "pageshow", (pageshowEvent) => {
|
|
135
|
+
// if (pageshowEvent.persisted === true) {
|
|
136
|
+
// removePageshowListener()
|
|
137
|
+
// removeResumeListener()
|
|
138
|
+
// callback(pageshowEvent)
|
|
139
|
+
// }
|
|
140
|
+
// })
|
|
141
|
+
// return () => {
|
|
142
|
+
// removeResumeListener()
|
|
143
|
+
// removePageshowListener()
|
|
144
|
+
// }
|
|
145
|
+
// }
|
|
146
|
+
|
|
147
|
+
const listenPageUnload = (callback) => {
|
|
148
|
+
const removePageHideListener = listenEvent(
|
|
149
|
+
window,
|
|
150
|
+
"pagehide",
|
|
151
|
+
(pageHideEvent) => {
|
|
152
|
+
if (pageHideEvent.persisted !== true) {
|
|
153
|
+
callback(pageHideEvent)
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
)
|
|
157
|
+
return removePageHideListener
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const listenEvent = (emitter, event, callback) => {
|
|
161
|
+
emitter.addEventListener(event, callback)
|
|
162
|
+
return () => {
|
|
163
|
+
emitter.removeEventListener(event, callback)
|
|
164
|
+
}
|
|
165
|
+
}
|