@jsenv/core 27.0.0-alpha.44 → 27.0.0-alpha.47
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/html_supervisor_installer.js +130 -39
- package/dist/html_supervisor_installer.js.map +32 -17
- package/dist/html_supervisor_setup.js +52 -49
- package/dist/html_supervisor_setup.js.map +11 -11
- package/package.json +4 -4
- package/src/build/start_build_server.js +87 -37
- package/src/dev/start_dev_server.js +95 -21
- package/src/execute/execute.js +1 -2
- package/src/omega/kitchen.js +33 -2
- package/src/omega/omega_server.js +2 -3
- package/src/omega/server/file_service.js +15 -1
- package/src/omega/url_graph/url_info_transformations.js +3 -1
- package/src/omega/url_graph.js +58 -6
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +27 -56
- package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -4
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +2 -2
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +132 -59
- package/src/plugins/html_supervisor/client/html_supervisor_setup.js +51 -49
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +30 -2
- package/src/plugins/plugins.js +6 -6
- package/src/test/execute_plan.js +2 -7
|
@@ -5,27 +5,24 @@
|
|
|
5
5
|
"../src/plugins/html_supervisor/client/html_supervisor_setup.js"
|
|
6
6
|
],
|
|
7
7
|
"sourcesContent": [
|
|
8
|
-
"window.__html_supervisor__ = {\n // \"html_supervisor_installer.js\" will implement\n // - \"
|
|
8
|
+
"window.__html_supervisor__ = {\n // \"html_supervisor_installer.js\" will implement\n // - \"addScriptToExecute\"\n // - \"superviseScriptTypeModule\"\n // - \"collectScriptResults\"\n // and take all executions in \"scriptsToExecute\" and implement their supervision\n scriptsToExecute: [],\n addScriptToExecute: (scriptToExecute) => {\n window.__html_supervisor__.scriptsToExecute.push(scriptToExecute)\n },\n superviseScript: ({ src, isInline, crossorigin, integrity }) => {\n window.__html_supervisor__.addScriptToExecute({\n src,\n type: \"js_classic\",\n isInline,\n currentScript: document.currentScript,\n execute: () => {\n return new Promise((resolve, reject) => {\n const script = document.createElement(\"script\")\n if (crossorigin) {\n script.crossorigin = crossorigin\n }\n if (integrity) {\n script.integrity = integrity\n }\n script.src = src\n const scriptUrl = new URL(src, window.location).href\n let lastWindowErrorUrl\n let lastWindowError\n const windowErrorCallback = (e) => {\n lastWindowErrorUrl = e.filename\n lastWindowError = e.error\n }\n const cleanup = () => {\n document.body.removeChild(script)\n window.removeEventListener(\"error\", windowErrorCallback)\n }\n window.addEventListener(\"error\", windowErrorCallback)\n script.addEventListener(\"error\", () => {\n cleanup()\n reject(src)\n })\n script.addEventListener(\"load\", () => {\n cleanup()\n if (lastWindowErrorUrl === scriptUrl) {\n reject(lastWindowError)\n } else {\n resolve()\n }\n })\n document.body.appendChild(script)\n })\n },\n })\n },\n superviseScriptTypeModule: () => {\n throw new Error(\"htmlSupervisor not installed\")\n },\n getScriptExecutionResults: () => {\n // wait for page to load before collecting script execution results\n const htmlReadyPromise = new Promise((resolve) => {\n if (document.readyState === \"complete\") {\n resolve()\n return\n }\n const loadCallback = () => {\n window.removeEventListener(\"load\", loadCallback)\n resolve()\n }\n window.addEventListener(\"load\", loadCallback)\n })\n return htmlReadyPromise.then(() => {\n return window.__html_supervisor__.collectScriptResults()\n })\n },\n collectScriptResults: () => {\n throw new Error(\"htmlSupervisor not installed\")\n },\n}\n"
|
|
9
9
|
],
|
|
10
10
|
"names": [
|
|
11
11
|
"window",
|
|
12
12
|
"__html_supervisor__",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
13
|
+
"scriptsToExecute",
|
|
14
|
+
"addScriptToExecute",
|
|
15
|
+
"scriptToExecute",
|
|
16
16
|
"push",
|
|
17
|
-
"collectScriptResults",
|
|
18
|
-
"Error",
|
|
19
|
-
"superviseScriptTypeModule",
|
|
20
17
|
"superviseScript",
|
|
21
18
|
"src",
|
|
19
|
+
"isInline",
|
|
22
20
|
"crossorigin",
|
|
23
21
|
"integrity",
|
|
24
22
|
"type",
|
|
25
|
-
"improveErrorWithFetch",
|
|
26
23
|
"currentScript",
|
|
27
24
|
"document",
|
|
28
|
-
"
|
|
25
|
+
"execute",
|
|
29
26
|
"Promise",
|
|
30
27
|
"resolve",
|
|
31
28
|
"reject",
|
|
@@ -47,11 +44,14 @@
|
|
|
47
44
|
"removeEventListener",
|
|
48
45
|
"addEventListener",
|
|
49
46
|
"appendChild",
|
|
47
|
+
"superviseScriptTypeModule",
|
|
48
|
+
"Error",
|
|
50
49
|
"getScriptExecutionResults",
|
|
51
50
|
"htmlReadyPromise",
|
|
52
51
|
"readyState",
|
|
53
52
|
"loadCallback",
|
|
54
|
-
"then"
|
|
53
|
+
"then",
|
|
54
|
+
"collectScriptResults"
|
|
55
55
|
],
|
|
56
|
-
"mappings": "AAAAA,MAAM,CAACC,mBAAP,GAA6B;AAC3B;AACA;AACA;AACA;AACA;AACAC,EAAAA,
|
|
56
|
+
"mappings": "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"
|
|
57
57
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "27.0.0-alpha.
|
|
3
|
+
"version": "27.0.0-alpha.47",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -60,15 +60,15 @@
|
|
|
60
60
|
"@financial-times/polyfill-useragent-normaliser": "2.0.1",
|
|
61
61
|
"@jsenv/abort": "4.1.2",
|
|
62
62
|
"@jsenv/babel-plugins": "1.0.2",
|
|
63
|
-
"@jsenv/filesystem": "3.
|
|
63
|
+
"@jsenv/filesystem": "3.2.2",
|
|
64
64
|
"@jsenv/importmap": "1.2.0",
|
|
65
65
|
"@jsenv/integrity": "0.0.1",
|
|
66
66
|
"@jsenv/log": "1.5.2",
|
|
67
67
|
"@jsenv/logger": "4.0.1",
|
|
68
68
|
"@jsenv/node-esm-resolution": "0.0.6",
|
|
69
|
-
"@jsenv/server": "12.6.
|
|
69
|
+
"@jsenv/server": "12.6.2",
|
|
70
70
|
"@jsenv/uneval": "1.6.0",
|
|
71
|
-
"@jsenv/utils": "1.
|
|
71
|
+
"@jsenv/utils": "1.7.0",
|
|
72
72
|
"construct-style-sheets-polyfill": "3.1.0",
|
|
73
73
|
"cssnano": "5.1.7",
|
|
74
74
|
"cssnano-preset-default": "5.2.7",
|
|
@@ -21,13 +21,15 @@ import {
|
|
|
21
21
|
pluginCORS,
|
|
22
22
|
fetchFileSystem,
|
|
23
23
|
} from "@jsenv/server"
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
assertAndNormalizeDirectoryUrl,
|
|
26
|
+
registerDirectoryLifecycle,
|
|
27
|
+
} from "@jsenv/filesystem"
|
|
25
28
|
import { createLogger } from "@jsenv/logger"
|
|
26
29
|
import { Abort } from "@jsenv/abort"
|
|
27
30
|
|
|
28
|
-
import {
|
|
31
|
+
import { initReloadableProcess } from "@jsenv/utils/process_reload/process_reload.js"
|
|
29
32
|
import { createTaskLog } from "@jsenv/utils/logs/task_log.js"
|
|
30
|
-
import { watchFiles } from "@jsenv/utils/file_watcher/file_watcher.js"
|
|
31
33
|
import { executeCommand } from "@jsenv/utils/command/command.js"
|
|
32
34
|
|
|
33
35
|
export const startBuildServer = async ({
|
|
@@ -45,43 +47,80 @@ export const startBuildServer = async ({
|
|
|
45
47
|
|
|
46
48
|
rootDirectoryUrl,
|
|
47
49
|
buildDirectoryUrl,
|
|
50
|
+
buildServerFiles = {
|
|
51
|
+
"./package.json": true,
|
|
52
|
+
"./jsenv.config.mjs": true,
|
|
53
|
+
},
|
|
54
|
+
buildServerMainFile,
|
|
55
|
+
buildServerAutoreload = false,
|
|
56
|
+
clientFiles = {
|
|
57
|
+
"./**": true,
|
|
58
|
+
"./**/.*/": false, // any folder starting with a dot is ignored (includes .git,.jsenv for instance)
|
|
59
|
+
"./dist/": false,
|
|
60
|
+
"./**/node_modules/": false,
|
|
61
|
+
},
|
|
62
|
+
cooldownBetweenFileEvents,
|
|
48
63
|
buildCommand,
|
|
49
64
|
mainBuildFileUrl = "/index.html",
|
|
50
|
-
watchedFilePatterns,
|
|
51
|
-
cooldownBetweenFileEvents,
|
|
52
|
-
autorestart,
|
|
53
65
|
}) => {
|
|
66
|
+
const logger = createLogger({ logLevel })
|
|
54
67
|
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
|
|
55
68
|
buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl)
|
|
56
69
|
|
|
57
|
-
const
|
|
58
|
-
signal,
|
|
70
|
+
const reloadableProcess = await initReloadableProcess({
|
|
59
71
|
handleSIGINT,
|
|
60
|
-
...(
|
|
72
|
+
...(buildServerAutoreload
|
|
61
73
|
? {
|
|
62
74
|
enabled: true,
|
|
63
|
-
logLevel:
|
|
64
|
-
|
|
65
|
-
urlsToWatch: [
|
|
66
|
-
...(autorestart.urlsToWatch || []),
|
|
67
|
-
new URL("package.json", rootDirectoryUrl),
|
|
68
|
-
new URL("jsenv.config.mjs", rootDirectoryUrl),
|
|
69
|
-
],
|
|
75
|
+
logLevel: "info",
|
|
76
|
+
fileToRestart: buildServerMainFile,
|
|
70
77
|
}
|
|
71
78
|
: {
|
|
72
79
|
enabled: false,
|
|
73
80
|
}),
|
|
74
81
|
})
|
|
75
|
-
if (
|
|
82
|
+
if (reloadableProcess.isPrimary) {
|
|
83
|
+
const buildServerFileChangeCallback = ({ relativeUrl, event }) => {
|
|
84
|
+
const url = new URL(relativeUrl, rootDirectoryUrl).href
|
|
85
|
+
if (buildServerAutoreload) {
|
|
86
|
+
logger.info(`file ${event} ${url} -> restarting server...`)
|
|
87
|
+
reloadableProcess.reload()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const stopWatchingBuildServerFiles = registerDirectoryLifecycle(
|
|
91
|
+
rootDirectoryUrl,
|
|
92
|
+
{
|
|
93
|
+
watchPatterns: {
|
|
94
|
+
[buildServerMainFile]: true,
|
|
95
|
+
...buildServerFiles,
|
|
96
|
+
},
|
|
97
|
+
cooldownBetweenFileEvents,
|
|
98
|
+
keepProcessAlive: false,
|
|
99
|
+
recursive: true,
|
|
100
|
+
added: ({ relativeUrl }) => {
|
|
101
|
+
buildServerFileChangeCallback({ relativeUrl, event: "added" })
|
|
102
|
+
},
|
|
103
|
+
updated: ({ relativeUrl }) => {
|
|
104
|
+
buildServerFileChangeCallback({ relativeUrl, event: "modified" })
|
|
105
|
+
},
|
|
106
|
+
removed: ({ relativeUrl }) => {
|
|
107
|
+
buildServerFileChangeCallback({ relativeUrl, event: "removed" })
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
)
|
|
111
|
+
signal.addEventListener("abort", () => {
|
|
112
|
+
stopWatchingBuildServerFiles()
|
|
113
|
+
})
|
|
76
114
|
return {
|
|
77
115
|
origin: `${protocol}://127.0.0.1:${port}`,
|
|
78
116
|
stop: () => {
|
|
79
|
-
|
|
117
|
+
stopWatchingBuildServerFiles()
|
|
118
|
+
|
|
119
|
+
reloadableProcess.stop()
|
|
80
120
|
},
|
|
81
121
|
}
|
|
82
122
|
}
|
|
83
|
-
signal =
|
|
84
|
-
const logger = createLogger({ logLevel })
|
|
123
|
+
signal = reloadableProcess.signal
|
|
85
124
|
|
|
86
125
|
let buildPromise
|
|
87
126
|
let buildAbortController
|
|
@@ -177,28 +216,39 @@ export const startBuildServer = async ({
|
|
|
177
216
|
})
|
|
178
217
|
logger.info(``)
|
|
179
218
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
219
|
+
runBuild()
|
|
220
|
+
const clientFileChangeCallback = ({ relativeUrl, event }) => {
|
|
221
|
+
const url = new URL(relativeUrl, rootDirectoryUrl).href
|
|
222
|
+
buildAbortController.abort()
|
|
223
|
+
// setTimeout is to ensure the abortController.abort() above
|
|
224
|
+
// is properly taken into account so that logs about abort comes first
|
|
225
|
+
// then logs about re-running the build happens
|
|
226
|
+
setTimeout(() => {
|
|
227
|
+
logger.info(`${url.slice(rootDirectoryUrl.length)} ${event} -> rebuild`)
|
|
228
|
+
runBuild()
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
|
|
232
|
+
watchPatterns: clientFiles,
|
|
183
233
|
cooldownBetweenFileEvents,
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
234
|
+
keepProcessAlive: false,
|
|
235
|
+
recursive: true,
|
|
236
|
+
added: ({ relativeUrl }) => {
|
|
237
|
+
clientFileChangeCallback({ relativeUrl, event: "added" })
|
|
238
|
+
},
|
|
239
|
+
updated: ({ relativeUrl }) => {
|
|
240
|
+
clientFileChangeCallback({ relativeUrl, event: "modified" })
|
|
241
|
+
},
|
|
242
|
+
removed: ({ relativeUrl }) => {
|
|
243
|
+
clientFileChangeCallback({ relativeUrl, event: "removed" })
|
|
193
244
|
},
|
|
194
245
|
})
|
|
195
|
-
signal.addEventListener("abort", () => {
|
|
196
|
-
unregisterDirectoryLifecyle()
|
|
197
|
-
})
|
|
198
|
-
runBuild()
|
|
199
246
|
return {
|
|
200
247
|
origin: server.origin,
|
|
201
|
-
stop: () =>
|
|
248
|
+
stop: () => {
|
|
249
|
+
stopWatchingClientFiles()
|
|
250
|
+
server.stop()
|
|
251
|
+
},
|
|
202
252
|
}
|
|
203
253
|
}
|
|
204
254
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
assertAndNormalizeDirectoryUrl,
|
|
3
|
+
registerDirectoryLifecycle,
|
|
4
|
+
} from "@jsenv/filesystem"
|
|
2
5
|
import { createLogger } from "@jsenv/logger"
|
|
3
6
|
|
|
4
|
-
import {
|
|
7
|
+
import { initReloadableProcess } from "@jsenv/utils/process_reload/process_reload.js"
|
|
5
8
|
import { createTaskLog } from "@jsenv/utils/logs/task_log.js"
|
|
6
9
|
import { getCorePlugins } from "@jsenv/core/src/plugins/plugins.js"
|
|
7
10
|
import { createUrlGraph } from "@jsenv/core/src/omega/url_graph.js"
|
|
@@ -14,7 +17,8 @@ import { jsenvPluginToolbar } from "./plugins/toolbar/jsenv_plugin_toolbar.js"
|
|
|
14
17
|
export const startDevServer = async ({
|
|
15
18
|
signal = new AbortController().signal,
|
|
16
19
|
handleSIGINT,
|
|
17
|
-
logLevel,
|
|
20
|
+
logLevel = "info",
|
|
21
|
+
omegaServerLogLevel = "warn",
|
|
18
22
|
port = 3456,
|
|
19
23
|
protocol = "http",
|
|
20
24
|
listenAnyIp,
|
|
@@ -25,6 +29,20 @@ export const startDevServer = async ({
|
|
|
25
29
|
privateKey,
|
|
26
30
|
keepProcessAlive = true,
|
|
27
31
|
rootDirectoryUrl,
|
|
32
|
+
devServerFiles = {
|
|
33
|
+
"./package.json": true,
|
|
34
|
+
"./jsenv.config.mjs": true,
|
|
35
|
+
},
|
|
36
|
+
devServerMainFile,
|
|
37
|
+
devServerAutoreload = false,
|
|
38
|
+
clientFiles = {
|
|
39
|
+
"./**": true,
|
|
40
|
+
"./**/.*/": false, // any folder starting with a dot is ignored (includes .git,.jsenv for instance)
|
|
41
|
+
"./**/dist/": false,
|
|
42
|
+
"./**/node_modules/": false,
|
|
43
|
+
},
|
|
44
|
+
cooldownBetweenFileEvents,
|
|
45
|
+
clientAutoreload = true,
|
|
28
46
|
|
|
29
47
|
sourcemaps = "inline",
|
|
30
48
|
plugins = [],
|
|
@@ -33,7 +51,6 @@ export const startDevServer = async ({
|
|
|
33
51
|
nodeEsmResolution,
|
|
34
52
|
fileSystemMagicResolution,
|
|
35
53
|
transpilation,
|
|
36
|
-
autoreload = true,
|
|
37
54
|
explorerGroups = {
|
|
38
55
|
source: {
|
|
39
56
|
"./*.html": true,
|
|
@@ -44,40 +61,92 @@ export const startDevServer = async ({
|
|
|
44
61
|
},
|
|
45
62
|
},
|
|
46
63
|
toolbar = false,
|
|
47
|
-
autorestart,
|
|
48
64
|
}) => {
|
|
65
|
+
const logger = createLogger({ logLevel })
|
|
49
66
|
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
|
|
50
|
-
const
|
|
67
|
+
const reloadableProcess = await initReloadableProcess({
|
|
51
68
|
signal,
|
|
52
69
|
handleSIGINT,
|
|
53
|
-
...(
|
|
70
|
+
...(devServerAutoreload
|
|
54
71
|
? {
|
|
55
72
|
enabled: true,
|
|
56
|
-
logLevel:
|
|
57
|
-
|
|
58
|
-
urlsToWatch: [
|
|
59
|
-
...(autorestart.urlsToWatch || []),
|
|
60
|
-
new URL("package.json", rootDirectoryUrl),
|
|
61
|
-
new URL("jsenv.config.mjs", rootDirectoryUrl),
|
|
62
|
-
],
|
|
73
|
+
logLevel: "warn",
|
|
74
|
+
fileToRestart: devServerMainFile,
|
|
63
75
|
}
|
|
64
76
|
: {
|
|
65
77
|
enabled: false,
|
|
66
78
|
}),
|
|
67
79
|
})
|
|
68
|
-
if (
|
|
80
|
+
if (reloadableProcess.isPrimary) {
|
|
81
|
+
const devServerFileChangeCallback = ({ relativeUrl, event }) => {
|
|
82
|
+
const url = new URL(relativeUrl, rootDirectoryUrl).href
|
|
83
|
+
if (devServerAutoreload) {
|
|
84
|
+
logger.info(`file ${event} ${url} -> restarting server...`)
|
|
85
|
+
reloadableProcess.reload()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const unregisterDevServerFilesWatcher = registerDirectoryLifecycle(
|
|
89
|
+
rootDirectoryUrl,
|
|
90
|
+
{
|
|
91
|
+
watchPatterns: {
|
|
92
|
+
[devServerMainFile]: true,
|
|
93
|
+
...devServerFiles,
|
|
94
|
+
},
|
|
95
|
+
cooldownBetweenFileEvents,
|
|
96
|
+
keepProcessAlive: false,
|
|
97
|
+
recursive: true,
|
|
98
|
+
added: ({ relativeUrl }) => {
|
|
99
|
+
devServerFileChangeCallback({ relativeUrl, event: "added" })
|
|
100
|
+
},
|
|
101
|
+
updated: ({ relativeUrl }) => {
|
|
102
|
+
devServerFileChangeCallback({ relativeUrl, event: "modified" })
|
|
103
|
+
},
|
|
104
|
+
removed: ({ relativeUrl }) => {
|
|
105
|
+
devServerFileChangeCallback({ relativeUrl, event: "removed" })
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
)
|
|
109
|
+
signal.addEventListener("abort", () => {
|
|
110
|
+
unregisterDevServerFilesWatcher()
|
|
111
|
+
})
|
|
69
112
|
return {
|
|
70
113
|
origin: `${protocol}://127.0.0.1:${port}`,
|
|
71
114
|
stop: () => {
|
|
72
|
-
|
|
115
|
+
unregisterDevServerFilesWatcher()
|
|
116
|
+
reloadableProcess.stop()
|
|
73
117
|
},
|
|
74
118
|
}
|
|
75
119
|
}
|
|
76
120
|
|
|
77
|
-
const logger = createLogger({ logLevel })
|
|
78
121
|
const startServerTask = createTaskLog(logger, "start server")
|
|
79
122
|
|
|
80
|
-
const
|
|
123
|
+
const clientFileChangeCallbackList = []
|
|
124
|
+
const clientFilesPruneCallbackList = []
|
|
125
|
+
const clientFileChangeCallback = ({ relativeUrl, event }) => {
|
|
126
|
+
const url = new URL(relativeUrl, rootDirectoryUrl).href
|
|
127
|
+
clientFileChangeCallbackList.forEach((callback) => {
|
|
128
|
+
callback({ url, event })
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
|
|
132
|
+
watchPatterns: clientFiles,
|
|
133
|
+
cooldownBetweenFileEvents,
|
|
134
|
+
keepProcessAlive: false,
|
|
135
|
+
recursive: true,
|
|
136
|
+
added: ({ relativeUrl }) => {
|
|
137
|
+
clientFileChangeCallback({ event: "added", relativeUrl })
|
|
138
|
+
},
|
|
139
|
+
updated: ({ relativeUrl }) => {
|
|
140
|
+
clientFileChangeCallback({ event: "modified", relativeUrl })
|
|
141
|
+
},
|
|
142
|
+
removed: ({ relativeUrl }) => {
|
|
143
|
+
clientFileChangeCallback({ event: "removed", relativeUrl })
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
const urlGraph = createUrlGraph({
|
|
147
|
+
clientFileChangeCallbackList,
|
|
148
|
+
clientFilesPruneCallbackList,
|
|
149
|
+
})
|
|
81
150
|
const kitchen = createKitchen({
|
|
82
151
|
signal,
|
|
83
152
|
logger,
|
|
@@ -97,7 +166,9 @@ export const startDevServer = async ({
|
|
|
97
166
|
nodeEsmResolution,
|
|
98
167
|
fileSystemMagicResolution,
|
|
99
168
|
transpilation,
|
|
100
|
-
|
|
169
|
+
clientAutoreload,
|
|
170
|
+
clientFileChangeCallbackList,
|
|
171
|
+
clientFilesPruneCallbackList,
|
|
101
172
|
}),
|
|
102
173
|
jsenvPluginExplorer({
|
|
103
174
|
groups: explorerGroups,
|
|
@@ -106,7 +177,7 @@ export const startDevServer = async ({
|
|
|
106
177
|
],
|
|
107
178
|
})
|
|
108
179
|
const server = await startOmegaServer({
|
|
109
|
-
|
|
180
|
+
logLevel: omegaServerLogLevel,
|
|
110
181
|
keepProcessAlive,
|
|
111
182
|
listenAnyIp,
|
|
112
183
|
port,
|
|
@@ -132,6 +203,9 @@ export const startDevServer = async ({
|
|
|
132
203
|
})
|
|
133
204
|
return {
|
|
134
205
|
origin: server.origin,
|
|
135
|
-
stop:
|
|
206
|
+
stop: () => {
|
|
207
|
+
stopWatchingClientFiles()
|
|
208
|
+
server.stop()
|
|
209
|
+
},
|
|
136
210
|
}
|
|
137
211
|
}
|
package/src/execute/execute.js
CHANGED
|
@@ -89,10 +89,9 @@ export const execute = async ({
|
|
|
89
89
|
}),
|
|
90
90
|
],
|
|
91
91
|
})
|
|
92
|
-
const serverLogger = createLogger({ logLevel: "warn" })
|
|
93
92
|
const server = await startOmegaServer({
|
|
94
93
|
signal: executeOperation.signal,
|
|
95
|
-
|
|
94
|
+
logLevel: "warn",
|
|
96
95
|
rootDirectoryUrl,
|
|
97
96
|
urlGraph,
|
|
98
97
|
kitchen,
|
package/src/omega/kitchen.js
CHANGED
|
@@ -619,7 +619,7 @@ export const createKitchen = ({
|
|
|
619
619
|
},
|
|
620
620
|
)
|
|
621
621
|
}
|
|
622
|
-
const cook = async ({ urlInfo, outDirectoryUrl, ...rest }) => {
|
|
622
|
+
const cook = memoizeCook(async ({ urlInfo, outDirectoryUrl, ...rest }) => {
|
|
623
623
|
outDirectoryUrl = outDirectoryUrl ? String(outDirectoryUrl) : undefined
|
|
624
624
|
|
|
625
625
|
const writeFiles = ({ gotError }) => {
|
|
@@ -654,7 +654,7 @@ export const createKitchen = ({
|
|
|
654
654
|
writeFiles({ gotError: true })
|
|
655
655
|
throw e
|
|
656
656
|
}
|
|
657
|
-
}
|
|
657
|
+
})
|
|
658
658
|
|
|
659
659
|
baseContext.cook = cook
|
|
660
660
|
|
|
@@ -684,6 +684,37 @@ export const createKitchen = ({
|
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
686
|
|
|
687
|
+
const memoizeCook = (cook) => {
|
|
688
|
+
const pendingDishes = new Map()
|
|
689
|
+
return async (params) => {
|
|
690
|
+
const { urlInfo } = params
|
|
691
|
+
const { url, modifiedTimestamp } = urlInfo
|
|
692
|
+
const pendingDish = pendingDishes.get(url)
|
|
693
|
+
if (pendingDish) {
|
|
694
|
+
if (!modifiedTimestamp) {
|
|
695
|
+
await pendingDish.promise
|
|
696
|
+
return
|
|
697
|
+
}
|
|
698
|
+
if (pendingDish.timestamp > modifiedTimestamp) {
|
|
699
|
+
await pendingDish.promise
|
|
700
|
+
return
|
|
701
|
+
}
|
|
702
|
+
pendingDishes.delete(url)
|
|
703
|
+
}
|
|
704
|
+
const timestamp = Date.now()
|
|
705
|
+
const promise = cook(params)
|
|
706
|
+
pendingDishes.set(url, {
|
|
707
|
+
timestamp,
|
|
708
|
+
promise,
|
|
709
|
+
})
|
|
710
|
+
try {
|
|
711
|
+
await promise
|
|
712
|
+
} finally {
|
|
713
|
+
pendingDishes.delete(url)
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
687
718
|
const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
|
|
688
719
|
Object.assign(urlInfo.data, reference.data)
|
|
689
720
|
Object.assign(urlInfo.timing, reference.timing)
|
|
@@ -8,14 +8,13 @@ import {
|
|
|
8
8
|
} from "@jsenv/server"
|
|
9
9
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js"
|
|
10
10
|
import { createCallbackListNotifiedOnce } from "@jsenv/abort"
|
|
11
|
-
import { loggerToLogLevel } from "@jsenv/logger"
|
|
12
11
|
|
|
13
12
|
import { createFileService } from "./server/file_service.js"
|
|
14
13
|
|
|
15
14
|
export const startOmegaServer = async ({
|
|
16
15
|
signal,
|
|
17
16
|
handleSIGINT,
|
|
18
|
-
|
|
17
|
+
logLevel,
|
|
19
18
|
protocol = "http",
|
|
20
19
|
http2 = protocol === "https",
|
|
21
20
|
privateKey,
|
|
@@ -48,7 +47,7 @@ export const startOmegaServer = async ({
|
|
|
48
47
|
stopOnSIGINT: handleSIGINT,
|
|
49
48
|
stopOnInternalError: false,
|
|
50
49
|
keepProcessAlive,
|
|
51
|
-
logLevel
|
|
50
|
+
logLevel,
|
|
52
51
|
startLog: false,
|
|
53
52
|
|
|
54
53
|
protocol,
|
|
@@ -47,11 +47,24 @@ export const createFileService = ({
|
|
|
47
47
|
type: "entry_point",
|
|
48
48
|
specifier: request.ressource,
|
|
49
49
|
})
|
|
50
|
+
const ifNoneMatch = request.headers["if-none-match"]
|
|
51
|
+
if (ifNoneMatch && urlInfo.contentEtag === ifNoneMatch) {
|
|
52
|
+
return {
|
|
53
|
+
status: 304,
|
|
54
|
+
headers: {
|
|
55
|
+
"cache-control": `private,max-age=0,must-revalidate`,
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
}
|
|
50
59
|
const referenceFromGraph = urlGraph.inferReference(
|
|
51
60
|
reference.url,
|
|
52
61
|
reference.parentUrl,
|
|
53
62
|
)
|
|
54
63
|
try {
|
|
64
|
+
// urlInfo objects are reused, they must be "reset" before cooking then again
|
|
65
|
+
if (!urlInfo.isInline) {
|
|
66
|
+
urlGraph.resetUrlInfo(urlInfo)
|
|
67
|
+
}
|
|
55
68
|
await kitchen.cook({
|
|
56
69
|
reference: referenceFromGraph || reference,
|
|
57
70
|
urlInfo,
|
|
@@ -60,7 +73,7 @@ export const createFileService = ({
|
|
|
60
73
|
[runtimeName]: runtimeVersion,
|
|
61
74
|
},
|
|
62
75
|
})
|
|
63
|
-
let { response, contentType, content } = urlInfo
|
|
76
|
+
let { response, contentType, content, contentEtag } = urlInfo
|
|
64
77
|
if (response) {
|
|
65
78
|
return response
|
|
66
79
|
}
|
|
@@ -71,6 +84,7 @@ export const createFileService = ({
|
|
|
71
84
|
"content-type": contentType,
|
|
72
85
|
"content-length": Buffer.byteLength(content),
|
|
73
86
|
"cache-control": `private,max-age=0,must-revalidate`,
|
|
87
|
+
"eTag": contentEtag,
|
|
74
88
|
},
|
|
75
89
|
body: content,
|
|
76
90
|
timing: urlInfo.timing,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { urlToRelativeUrl } from "@jsenv/filesystem"
|
|
1
|
+
import { bufferToEtag, urlToRelativeUrl } from "@jsenv/filesystem"
|
|
2
|
+
|
|
2
3
|
import { composeTwoSourcemaps } from "@jsenv/utils/sourcemap/sourcemap_composition_v3.js"
|
|
3
4
|
import {
|
|
4
5
|
SOURCEMAP,
|
|
@@ -163,6 +164,7 @@ export const createUrlInfoTransformer = ({
|
|
|
163
164
|
})
|
|
164
165
|
}
|
|
165
166
|
}
|
|
167
|
+
urlInfo.contentEtag = bufferToEtag(Buffer.from(urlInfo.content))
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
return {
|