@jsenv/core 27.6.1 → 27.7.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/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 +21292 -21641
- package/package.json +3 -3
- package/src/build/build.js +15 -13
- package/src/dev/start_dev_server.js +6 -10
- 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/omega_server.js +11 -0
- package/src/omega/server/file_service.js +2 -18
- package/src/plugins/autoreload/client/autoreload.js +3 -4
- 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 +3 -1
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "27.
|
|
3
|
+
"version": "27.7.0",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@jsenv/integrity": "0.0.1",
|
|
74
74
|
"@jsenv/log": "3.1.0",
|
|
75
75
|
"@jsenv/node-esm-resolution": "0.1.0",
|
|
76
|
-
"@jsenv/server": "13.
|
|
76
|
+
"@jsenv/server": "13.1.0",
|
|
77
77
|
"@jsenv/sourcemap": "1.0.4",
|
|
78
78
|
"@jsenv/uneval": "1.6.0",
|
|
79
79
|
"@jsenv/url-meta": "7.0.0",
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
"eslint-plugin-html": "7.0.0",
|
|
110
110
|
"eslint-plugin-import": "2.26.0",
|
|
111
111
|
"eslint-plugin-react": "7.30.1",
|
|
112
|
-
"playwright": "1.
|
|
112
|
+
"playwright": "1.24.1",
|
|
113
113
|
"prettier": "2.7.1"
|
|
114
114
|
}
|
|
115
115
|
}
|
package/src/build/build.js
CHANGED
|
@@ -47,6 +47,20 @@ import { createVersionGenerator } from "./version_generator.js"
|
|
|
47
47
|
import { injectServiceWorkerUrls } from "./inject_service_worker_urls.js"
|
|
48
48
|
import { resyncRessourceHints } from "./resync_ressource_hints.js"
|
|
49
49
|
|
|
50
|
+
// default runtimeCompat corresponds to
|
|
51
|
+
// "we can keep <script type="module"> intact":
|
|
52
|
+
// so script_type_module + dynamic_import + import_meta
|
|
53
|
+
export const defaultRuntimeCompat = {
|
|
54
|
+
// android: "8",
|
|
55
|
+
chrome: "64",
|
|
56
|
+
edge: "79",
|
|
57
|
+
firefox: "67",
|
|
58
|
+
ios: "12",
|
|
59
|
+
opera: "51",
|
|
60
|
+
safari: "11.3",
|
|
61
|
+
samsung: "9.2",
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
/**
|
|
51
65
|
* Generate an optimized version of source files into a directory
|
|
52
66
|
* @param {Object} buildParameters
|
|
@@ -85,19 +99,7 @@ export const build = async ({
|
|
|
85
99
|
entryPoints = {},
|
|
86
100
|
baseUrl = "/",
|
|
87
101
|
|
|
88
|
-
|
|
89
|
-
// "we can keep <script type="module"> intact":
|
|
90
|
-
// so script_type_module + dynamic_import + import_meta
|
|
91
|
-
runtimeCompat = {
|
|
92
|
-
// android: "8",
|
|
93
|
-
chrome: "64",
|
|
94
|
-
edge: "79",
|
|
95
|
-
firefox: "67",
|
|
96
|
-
ios: "12",
|
|
97
|
-
opera: "51",
|
|
98
|
-
safari: "11.3",
|
|
99
|
-
samsung: "9.2",
|
|
100
|
-
},
|
|
102
|
+
runtimeCompat = defaultRuntimeCompat,
|
|
101
103
|
plugins = [],
|
|
102
104
|
sourcemaps = false,
|
|
103
105
|
sourcemapsSourcesContent,
|
|
@@ -7,6 +7,7 @@ import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
|
|
|
7
7
|
import { createLogger, loggerToLevels, createTaskLog } from "@jsenv/log"
|
|
8
8
|
import { getCallerPosition } from "@jsenv/urls"
|
|
9
9
|
|
|
10
|
+
import { defaultRuntimeCompat } from "@jsenv/core/src/build/build.js"
|
|
10
11
|
import { createReloadableWorker } from "@jsenv/core/src/helpers/worker_reload.js"
|
|
11
12
|
import { startOmegaServer } from "@jsenv/core/src/omega/omega_server.js"
|
|
12
13
|
|
|
@@ -41,16 +42,10 @@ export const startDevServer = async ({
|
|
|
41
42
|
devServerMainFile = getCallerPosition().url,
|
|
42
43
|
cooldownBetweenFileEvents,
|
|
43
44
|
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
// and "jsenv_plugin_node_runtime.js" applies only during build made for node.js
|
|
49
|
-
runtimeCompat = {
|
|
50
|
-
chrome: "100",
|
|
51
|
-
firefox: "100",
|
|
52
|
-
safari: "15.5",
|
|
53
|
-
},
|
|
45
|
+
// runtimeCompat is the runtimeCompat for the build
|
|
46
|
+
// when specified, dev server use it to warn in case
|
|
47
|
+
// code would be supported during dev but not after build
|
|
48
|
+
runtimeCompat = defaultRuntimeCompat,
|
|
54
49
|
plugins = [],
|
|
55
50
|
urlAnalysis = {},
|
|
56
51
|
htmlSupervisor = true,
|
|
@@ -162,6 +157,7 @@ export const startDevServer = async ({
|
|
|
162
157
|
rootDirectoryUrl,
|
|
163
158
|
scenario: "dev",
|
|
164
159
|
runtimeCompat,
|
|
160
|
+
|
|
165
161
|
plugins,
|
|
166
162
|
urlAnalysis,
|
|
167
163
|
htmlSupervisor,
|
|
@@ -2,7 +2,7 @@ import { createRuntimeFromPlaywright } from "./from_playwright.js"
|
|
|
2
2
|
|
|
3
3
|
export const chromium = createRuntimeFromPlaywright({
|
|
4
4
|
browserName: "chromium",
|
|
5
|
-
browserVersion: "104.0.5112.
|
|
5
|
+
browserVersion: "104.0.5112.48", // to update, check https://github.com/microsoft/playwright/releases
|
|
6
6
|
coveragePlaywrightAPIAvailable: true,
|
|
7
7
|
})
|
|
8
8
|
export const chromiumIsolatedTab = chromium.isolatedTab
|
|
@@ -2,6 +2,6 @@ import { createRuntimeFromPlaywright } from "./from_playwright.js"
|
|
|
2
2
|
|
|
3
3
|
export const firefox = createRuntimeFromPlaywright({
|
|
4
4
|
browserName: "firefox",
|
|
5
|
-
browserVersion: "
|
|
5
|
+
browserVersion: "102.0", // to update, check https://github.com/microsoft/playwright/releases
|
|
6
6
|
})
|
|
7
7
|
export const firefoxIsolatedTab = firefox.isolatedTab
|
|
@@ -2,7 +2,7 @@ import { createRuntimeFromPlaywright } from "./from_playwright.js"
|
|
|
2
2
|
|
|
3
3
|
export const webkit = createRuntimeFromPlaywright({
|
|
4
4
|
browserName: "webkit",
|
|
5
|
-
browserVersion: "
|
|
5
|
+
browserVersion: "16.0", // to update, check https://github.com/microsoft/playwright/releases
|
|
6
6
|
ignoreErrorHook: (error) => {
|
|
7
7
|
// we catch error during execution but safari throw unhandled rejection
|
|
8
8
|
// in a non-deterministic way.
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
jsenvServiceErrorHandler,
|
|
6
6
|
} from "@jsenv/server"
|
|
7
7
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js"
|
|
8
|
+
import { createServerEventsDispatcher } from "@jsenv/core/src/plugins/server_events/server_events_dispatcher.js"
|
|
8
9
|
|
|
9
10
|
import { createFileService } from "./server/file_service.js"
|
|
10
11
|
|
|
@@ -43,6 +44,10 @@ export const startOmegaServer = async ({
|
|
|
43
44
|
writeGeneratedFiles,
|
|
44
45
|
}) => {
|
|
45
46
|
const serverStopCallbacks = []
|
|
47
|
+
const serverEventsDispatcher = createServerEventsDispatcher()
|
|
48
|
+
serverStopCallbacks.push(() => {
|
|
49
|
+
serverEventsDispatcher.destroy()
|
|
50
|
+
})
|
|
46
51
|
const server = await startServer({
|
|
47
52
|
signal,
|
|
48
53
|
stopOnExit: false,
|
|
@@ -79,6 +84,7 @@ export const startOmegaServer = async ({
|
|
|
79
84
|
signal,
|
|
80
85
|
logLevel,
|
|
81
86
|
serverStopCallbacks,
|
|
87
|
+
serverEventsDispatcher,
|
|
82
88
|
|
|
83
89
|
rootDirectoryUrl,
|
|
84
90
|
scenario,
|
|
@@ -99,6 +105,11 @@ export const startOmegaServer = async ({
|
|
|
99
105
|
sourcemapsSourcesContent,
|
|
100
106
|
writeGeneratedFiles,
|
|
101
107
|
}),
|
|
108
|
+
handleWebsocket: (websocket, { request }) => {
|
|
109
|
+
if (request.headers["sec-websocket-protocol"] === "jsenv") {
|
|
110
|
+
serverEventsDispatcher.addWebsocket(websocket, request)
|
|
111
|
+
}
|
|
112
|
+
},
|
|
102
113
|
},
|
|
103
114
|
{
|
|
104
115
|
name: "jsenv:omega_error_handler",
|
|
@@ -10,7 +10,6 @@ import { URL_META } from "@jsenv/url-meta"
|
|
|
10
10
|
import { getCorePlugins } from "@jsenv/core/src/plugins/plugins.js"
|
|
11
11
|
import { createUrlGraph } from "@jsenv/core/src/omega/url_graph.js"
|
|
12
12
|
import { createKitchen } from "@jsenv/core/src/omega/kitchen.js"
|
|
13
|
-
import { createServerEventsDispatcher } from "@jsenv/core/src/plugins/server_events/server_events_dispatcher.js"
|
|
14
13
|
import { jsenvPluginServerEventsClientInjection } from "@jsenv/core/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js"
|
|
15
14
|
import { parseUserAgentHeader } from "./user_agent.js"
|
|
16
15
|
|
|
@@ -18,6 +17,7 @@ export const createFileService = ({
|
|
|
18
17
|
signal,
|
|
19
18
|
logLevel,
|
|
20
19
|
serverStopCallbacks,
|
|
20
|
+
serverEventsDispatcher,
|
|
21
21
|
|
|
22
22
|
rootDirectoryUrl,
|
|
23
23
|
scenario,
|
|
@@ -152,10 +152,6 @@ export const createFileService = ({
|
|
|
152
152
|
})
|
|
153
153
|
const serverEventNames = Object.keys(allServerEvents)
|
|
154
154
|
if (serverEventNames.length > 0) {
|
|
155
|
-
const serverEventsDispatcher = createServerEventsDispatcher()
|
|
156
|
-
serverStopCallbacks.push(() => {
|
|
157
|
-
serverEventsDispatcher.destroy()
|
|
158
|
-
})
|
|
159
155
|
Object.keys(allServerEvents).forEach((serverEventName) => {
|
|
160
156
|
allServerEvents[serverEventName]({
|
|
161
157
|
rootDirectoryUrl,
|
|
@@ -169,19 +165,7 @@ export const createFileService = ({
|
|
|
169
165
|
},
|
|
170
166
|
})
|
|
171
167
|
})
|
|
172
|
-
// "
|
|
173
|
-
kitchen.pluginController.unshiftPlugin({
|
|
174
|
-
name: "jsenv:provide_server_events",
|
|
175
|
-
serve: (request) => {
|
|
176
|
-
const { accept } = request.headers
|
|
177
|
-
if (accept && accept.includes("text/event-stream")) {
|
|
178
|
-
const room = serverEventsDispatcher.addRoom(request)
|
|
179
|
-
return room.join(request)
|
|
180
|
-
}
|
|
181
|
-
return null
|
|
182
|
-
},
|
|
183
|
-
})
|
|
184
|
-
// "push" so that event source client connection can be put as early as possible in html
|
|
168
|
+
// "pushPlugin" so that event source client connection can be put as early as possible in html
|
|
185
169
|
kitchen.pluginController.pushPlugin(
|
|
186
170
|
jsenvPluginServerEventsClientInjection(),
|
|
187
171
|
)
|
|
@@ -192,10 +192,9 @@ const applyHotReload = async ({ hotInstructions }) => {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
window.__reloader__ = reloader
|
|
195
|
-
window.__server_events__.
|
|
196
|
-
reload: (
|
|
197
|
-
|
|
198
|
-
reloader.addMessage(reloadMessage)
|
|
195
|
+
window.__server_events__.listenEvents({
|
|
196
|
+
reload: (reloadServerEvent) => {
|
|
197
|
+
reloader.addMessage(reloadServerEvent.data)
|
|
199
198
|
},
|
|
200
199
|
})
|
|
201
200
|
|
|
@@ -123,46 +123,52 @@ export const formatError = (
|
|
|
123
123
|
const onErrorLocated = (urlSite) => {
|
|
124
124
|
errorUrlSite = urlSite
|
|
125
125
|
errorDetailsPromiseReference.current = (async () => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return null
|
|
134
|
-
}
|
|
135
|
-
const causeInfo = await response.json()
|
|
136
|
-
if (!causeInfo) {
|
|
137
|
-
return null
|
|
138
|
-
}
|
|
126
|
+
try {
|
|
127
|
+
if (errorMeta.type === "dynamic_import_fetch_error") {
|
|
128
|
+
const response = await window.fetch(
|
|
129
|
+
`/__get_error_cause__/${
|
|
130
|
+
urlSite.isInline ? urlSite.originalUrl : urlSite.url
|
|
131
|
+
}`,
|
|
132
|
+
)
|
|
139
133
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
134
|
+
if (response.status !== 200) {
|
|
135
|
+
return null
|
|
136
|
+
}
|
|
137
|
+
const causeInfo = await response.json()
|
|
138
|
+
if (!causeInfo) {
|
|
139
|
+
return null
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const causeText =
|
|
143
|
+
causeInfo.code === "NOT_FOUND"
|
|
144
|
+
? formatErrorText({
|
|
145
|
+
message: causeInfo.reason,
|
|
146
|
+
stack: causeInfo.codeFrame,
|
|
147
|
+
})
|
|
148
|
+
: formatErrorText({
|
|
149
|
+
message: causeInfo.stack,
|
|
150
|
+
stack: causeInfo.codeFrame,
|
|
151
|
+
})
|
|
152
|
+
return {
|
|
153
|
+
cause: causeText,
|
|
154
|
+
}
|
|
160
155
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
if (urlSite.line !== undefined) {
|
|
157
|
+
let ressourceToFetch = `/__get_code_frame__/${formatUrlWithLineAndColumn(
|
|
158
|
+
urlSite,
|
|
159
|
+
)}`
|
|
160
|
+
if (!Error.captureStackTrace) {
|
|
161
|
+
ressourceToFetch += `?remap`
|
|
162
|
+
}
|
|
163
|
+
const response = await window.fetch(ressourceToFetch)
|
|
164
|
+
const codeFrame = await response.text()
|
|
165
|
+
return {
|
|
166
|
+
codeFrame: formatErrorText({ message: codeFrame }),
|
|
167
|
+
}
|
|
165
168
|
}
|
|
169
|
+
} catch (e) {
|
|
170
|
+
// happens if server is closed for instance
|
|
171
|
+
return null
|
|
166
172
|
}
|
|
167
173
|
return null
|
|
168
174
|
})()
|
|
@@ -132,9 +132,7 @@ export const installHtmlSupervisor = ({
|
|
|
132
132
|
}
|
|
133
133
|
executionResult.error = error
|
|
134
134
|
onExecutionSettled(src, executionResult)
|
|
135
|
-
onExecutionError(executionResult, {
|
|
136
|
-
currentScript,
|
|
137
|
-
})
|
|
135
|
+
onExecutionError(executionResult, { currentScript })
|
|
138
136
|
if (errorExposureInConsole) {
|
|
139
137
|
if (typeof window.reportError === "function") {
|
|
140
138
|
window.reportError(error)
|
|
@@ -181,7 +179,6 @@ export const installHtmlSupervisor = ({
|
|
|
181
179
|
const useDeferQueue =
|
|
182
180
|
scriptToExecute.defer || scriptToExecute.type === "module"
|
|
183
181
|
if (useDeferQueue) {
|
|
184
|
-
// defer must wait for classic script to be done
|
|
185
182
|
const classicExecutionPromise = classicExecutionQueue.getPromise()
|
|
186
183
|
if (classicExecutionPromise) {
|
|
187
184
|
deferedExecutionQueue.waitFor(classicExecutionPromise)
|
|
@@ -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
|
})
|
|
@@ -132,7 +132,9 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
132
132
|
code: causeInfo.code,
|
|
133
133
|
message: causeInfo.message,
|
|
134
134
|
reason: causeInfo.reason,
|
|
135
|
-
stack:
|
|
135
|
+
stack: errorBaseUrl
|
|
136
|
+
? `stack mocked for snapshot`
|
|
137
|
+
: causeInfo.stack,
|
|
136
138
|
codeFrame: causeInfo.traceMessage,
|
|
137
139
|
}
|
|
138
140
|
: null,
|
|
@@ -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
|
+
}
|