@jsenv/core 31.2.0 → 32.0.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/v8_coverage.js +36 -23
- package/dist/main.js +482 -546
- package/package.json +5 -5
- package/src/basic_fetch.js +42 -0
- package/src/build/build.js +81 -93
- package/src/build/start_build_server.js +32 -112
- package/src/dev/file_service.js +49 -66
- package/src/dev/start_dev_server.js +43 -94
- package/src/execute/execute.js +4 -1
- package/src/execute/runtimes/node/node_child_process.js +0 -1
- package/src/jsenv_internal_directory.js +18 -0
- package/src/kitchen/kitchen.js +2 -0
- package/src/lookup_package_directory.js +34 -0
- package/src/plugins/explorer/jsenv_plugin_explorer.js +5 -4
- package/src/plugins/plugins.js +4 -16
- package/src/plugins/url_resolution/jsenv_plugin_url_resolution.js +2 -2
- package/src/test/coverage/v8_coverage_node_directory.js +4 -2
- package/src/test/execute_plan.js +6 -67
- package/src/test/execute_test_plan.js +199 -45
- package/src/watch_source_files.js +50 -0
package/src/dev/file_service.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs"
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
composeTwoResponses,
|
|
6
|
-
} from "@jsenv/server"
|
|
7
|
-
import { registerDirectoryLifecycle, bufferToEtag } from "@jsenv/filesystem"
|
|
8
|
-
import { urlIsInsideOf, moveUrl, asUrlWithoutSearch } from "@jsenv/urls"
|
|
2
|
+
import { serveDirectory, composeTwoResponses } from "@jsenv/server"
|
|
3
|
+
import { bufferToEtag } from "@jsenv/filesystem"
|
|
4
|
+
import { moveUrl, asUrlWithoutSearch } from "@jsenv/urls"
|
|
9
5
|
import { URL_META } from "@jsenv/url-meta"
|
|
10
6
|
|
|
7
|
+
import { determineJsenvInternalDirectoryUrl } from "../jsenv_internal_directory.js"
|
|
8
|
+
import { watchSourceFiles } from "../watch_source_files.js"
|
|
9
|
+
import { explorerHtmlFileUrl } from "@jsenv/core/src/plugins/explorer/jsenv_plugin_explorer.js"
|
|
11
10
|
import { createUrlGraph } from "@jsenv/core/src/kitchen/url_graph.js"
|
|
12
11
|
import { createKitchen } from "@jsenv/core/src/kitchen/kitchen.js"
|
|
13
12
|
import { RUNTIME_COMPAT } from "@jsenv/core/src/kitchen/compat/runtime_compat.js"
|
|
@@ -22,7 +21,9 @@ export const createFileService = ({
|
|
|
22
21
|
serverEventsDispatcher,
|
|
23
22
|
contextCache,
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
sourceDirectoryUrl,
|
|
25
|
+
sourceMainFilePath,
|
|
26
|
+
sourceFilesConfig,
|
|
26
27
|
runtimeCompat,
|
|
27
28
|
|
|
28
29
|
plugins,
|
|
@@ -32,8 +33,6 @@ export const createFileService = ({
|
|
|
32
33
|
supervisor,
|
|
33
34
|
transpilation,
|
|
34
35
|
clientAutoreload,
|
|
35
|
-
clientFiles,
|
|
36
|
-
clientMainFileUrl,
|
|
37
36
|
cooldownBetweenFileEvents,
|
|
38
37
|
explorer,
|
|
39
38
|
cacheControl,
|
|
@@ -43,45 +42,22 @@ export const createFileService = ({
|
|
|
43
42
|
sourcemapsSourcesContent,
|
|
44
43
|
writeGeneratedFiles,
|
|
45
44
|
}) => {
|
|
46
|
-
const jsenvDirectoryUrl = new URL(".jsenv/", rootDirectoryUrl).href
|
|
47
|
-
|
|
48
45
|
const clientFileChangeCallbackList = []
|
|
49
46
|
const clientFilesPruneCallbackList = []
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const onFileChange = (url) => {
|
|
56
|
-
clientFileChangeCallbackList.forEach((callback) => {
|
|
57
|
-
callback(url)
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
|
|
61
|
-
watchPatterns: clientFilePatterns,
|
|
62
|
-
cooldownBetweenFileEvents,
|
|
63
|
-
keepProcessAlive: false,
|
|
64
|
-
recursive: true,
|
|
65
|
-
added: ({ relativeUrl }) => {
|
|
66
|
-
onFileChange({
|
|
67
|
-
url: new URL(relativeUrl, rootDirectoryUrl).href,
|
|
68
|
-
event: "added",
|
|
47
|
+
const stopWatchingSourceFiles = watchSourceFiles(
|
|
48
|
+
sourceDirectoryUrl,
|
|
49
|
+
(fileInfo) => {
|
|
50
|
+
clientFileChangeCallbackList.forEach((callback) => {
|
|
51
|
+
callback(fileInfo)
|
|
69
52
|
})
|
|
70
53
|
},
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
})
|
|
54
|
+
{
|
|
55
|
+
sourceFilesConfig,
|
|
56
|
+
keepProcessAlive: false,
|
|
57
|
+
cooldownBetweenFileEvents,
|
|
76
58
|
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
url: new URL(relativeUrl, rootDirectoryUrl).href,
|
|
80
|
-
event: "removed",
|
|
81
|
-
})
|
|
82
|
-
},
|
|
83
|
-
})
|
|
84
|
-
serverStopCallbacks.push(stopWatchingClientFiles)
|
|
59
|
+
)
|
|
60
|
+
serverStopCallbacks.push(stopWatchingSourceFiles)
|
|
85
61
|
|
|
86
62
|
const getOrCreateContext = (request) => {
|
|
87
63
|
const { runtimeName, runtimeVersion } = parseUserAgentHeader(
|
|
@@ -93,8 +69,8 @@ export const createFileService = ({
|
|
|
93
69
|
return existingContext
|
|
94
70
|
}
|
|
95
71
|
const watchAssociations = URL_META.resolveAssociations(
|
|
96
|
-
{ watch:
|
|
97
|
-
|
|
72
|
+
{ watch: stopWatchingSourceFiles.watchPatterns },
|
|
73
|
+
sourceDirectoryUrl,
|
|
98
74
|
)
|
|
99
75
|
const urlGraph = createUrlGraph()
|
|
100
76
|
clientFileChangeCallbackList.push(({ url }) => {
|
|
@@ -114,10 +90,22 @@ export const createFileService = ({
|
|
|
114
90
|
})
|
|
115
91
|
})
|
|
116
92
|
const clientRuntimeCompat = { [runtimeName]: runtimeVersion }
|
|
93
|
+
const jsenvInternalDirectoryUrl =
|
|
94
|
+
determineJsenvInternalDirectoryUrl(sourceDirectoryUrl)
|
|
95
|
+
|
|
96
|
+
let mainFileUrl
|
|
97
|
+
if (sourceMainFilePath === undefined) {
|
|
98
|
+
mainFileUrl = explorer
|
|
99
|
+
? String(explorerHtmlFileUrl)
|
|
100
|
+
: String(new URL("./index.html", sourceDirectoryUrl))
|
|
101
|
+
} else {
|
|
102
|
+
mainFileUrl = String(new URL(sourceMainFilePath, sourceDirectoryUrl))
|
|
103
|
+
}
|
|
117
104
|
const kitchen = createKitchen({
|
|
118
105
|
signal,
|
|
119
106
|
logLevel,
|
|
120
|
-
rootDirectoryUrl,
|
|
107
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
108
|
+
jsenvInternalDirectoryUrl,
|
|
121
109
|
urlGraph,
|
|
122
110
|
dev: true,
|
|
123
111
|
runtimeCompat,
|
|
@@ -132,7 +120,8 @@ export const createFileService = ({
|
|
|
132
120
|
plugins: [
|
|
133
121
|
...plugins,
|
|
134
122
|
...getCorePlugins({
|
|
135
|
-
rootDirectoryUrl,
|
|
123
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
124
|
+
mainFileUrl,
|
|
136
125
|
runtimeCompat,
|
|
137
126
|
|
|
138
127
|
urlAnalysis,
|
|
@@ -141,7 +130,6 @@ export const createFileService = ({
|
|
|
141
130
|
supervisor,
|
|
142
131
|
transpilation,
|
|
143
132
|
|
|
144
|
-
clientMainFileUrl,
|
|
145
133
|
clientAutoreload,
|
|
146
134
|
clientFileChangeCallbackList,
|
|
147
135
|
clientFilesPruneCallbackList,
|
|
@@ -156,7 +144,10 @@ export const createFileService = ({
|
|
|
156
144
|
sourcemapsSourcesProtocol,
|
|
157
145
|
sourcemapsSourcesContent,
|
|
158
146
|
writeGeneratedFiles,
|
|
159
|
-
outDirectoryUrl:
|
|
147
|
+
outDirectoryUrl: new URL(
|
|
148
|
+
`${runtimeName}@${runtimeVersion}/`,
|
|
149
|
+
jsenvInternalDirectoryUrl,
|
|
150
|
+
),
|
|
160
151
|
})
|
|
161
152
|
urlGraph.createUrlInfoCallbackRef.current = (urlInfo) => {
|
|
162
153
|
const { watch } = URL_META.applyAssociations({
|
|
@@ -231,7 +222,7 @@ export const createFileService = ({
|
|
|
231
222
|
if (serverEventNames.length > 0) {
|
|
232
223
|
Object.keys(allServerEvents).forEach((serverEventName) => {
|
|
233
224
|
allServerEvents[serverEventName]({
|
|
234
|
-
rootDirectoryUrl,
|
|
225
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
235
226
|
urlGraph,
|
|
236
227
|
dev: true,
|
|
237
228
|
sendServerEvent: (data) => {
|
|
@@ -250,7 +241,7 @@ export const createFileService = ({
|
|
|
250
241
|
}
|
|
251
242
|
|
|
252
243
|
const context = {
|
|
253
|
-
rootDirectoryUrl,
|
|
244
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
254
245
|
dev: true,
|
|
255
246
|
runtimeName,
|
|
256
247
|
runtimeVersion,
|
|
@@ -262,14 +253,6 @@ export const createFileService = ({
|
|
|
262
253
|
}
|
|
263
254
|
|
|
264
255
|
return async (request) => {
|
|
265
|
-
// serve file inside ".jsenv" directory
|
|
266
|
-
const requestFileUrl = new URL(request.resource.slice(1), rootDirectoryUrl)
|
|
267
|
-
.href
|
|
268
|
-
if (urlIsInsideOf(requestFileUrl, jsenvDirectoryUrl)) {
|
|
269
|
-
return fetchFileSystem(requestFileUrl, {
|
|
270
|
-
headers: request.headers,
|
|
271
|
-
})
|
|
272
|
-
}
|
|
273
256
|
const { urlGraph, kitchen } = getOrCreateContext(request)
|
|
274
257
|
const responseFromPlugin =
|
|
275
258
|
await kitchen.pluginController.callAsyncHooksUntil(
|
|
@@ -281,14 +264,14 @@ export const createFileService = ({
|
|
|
281
264
|
return responseFromPlugin
|
|
282
265
|
}
|
|
283
266
|
let reference
|
|
284
|
-
const parentUrl = inferParentFromRequest(request,
|
|
267
|
+
const parentUrl = inferParentFromRequest(request, sourceDirectoryUrl)
|
|
285
268
|
if (parentUrl) {
|
|
286
269
|
reference = urlGraph.inferReference(request.resource, parentUrl)
|
|
287
270
|
}
|
|
288
271
|
if (!reference) {
|
|
289
272
|
const entryPoint = kitchen.injectReference({
|
|
290
|
-
trace: { message: parentUrl ||
|
|
291
|
-
parentUrl: parentUrl ||
|
|
273
|
+
trace: { message: parentUrl || sourceDirectoryUrl },
|
|
274
|
+
parentUrl: parentUrl || sourceDirectoryUrl,
|
|
292
275
|
type: "http_request",
|
|
293
276
|
specifier: request.resource,
|
|
294
277
|
})
|
|
@@ -424,7 +407,7 @@ export const createFileService = ({
|
|
|
424
407
|
accept: "text/html",
|
|
425
408
|
},
|
|
426
409
|
canReadDirectory: true,
|
|
427
|
-
rootDirectoryUrl,
|
|
410
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
428
411
|
})
|
|
429
412
|
}
|
|
430
413
|
if (code === "NOT_ALLOWED") {
|
|
@@ -452,7 +435,7 @@ export const createFileService = ({
|
|
|
452
435
|
}
|
|
453
436
|
}
|
|
454
437
|
|
|
455
|
-
const inferParentFromRequest = (request,
|
|
438
|
+
const inferParentFromRequest = (request, sourceDirectoryUrl) => {
|
|
456
439
|
const { referer } = request.headers
|
|
457
440
|
if (!referer) {
|
|
458
441
|
return null
|
|
@@ -468,7 +451,7 @@ const inferParentFromRequest = (request, rootDirectoryUrl) => {
|
|
|
468
451
|
return moveUrl({
|
|
469
452
|
url: referer,
|
|
470
453
|
from: `${request.origin}/`,
|
|
471
|
-
to:
|
|
454
|
+
to: sourceDirectoryUrl,
|
|
472
455
|
preferAbsolute: true,
|
|
473
456
|
})
|
|
474
457
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
validateDirectoryUrl,
|
|
4
|
-
registerDirectoryLifecycle,
|
|
5
|
-
} from "@jsenv/filesystem"
|
|
1
|
+
import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
6
2
|
import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
|
|
7
3
|
import { createLogger, createTaskLog } from "@jsenv/log"
|
|
8
|
-
import { getCallerPosition } from "@jsenv/urls"
|
|
9
4
|
import {
|
|
10
5
|
jsenvAccessControlAllowedHeaders,
|
|
11
6
|
startServer,
|
|
@@ -16,7 +11,6 @@ import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/in
|
|
|
16
11
|
|
|
17
12
|
import { createServerEventsDispatcher } from "@jsenv/core/src/plugins/server_events/server_events_dispatcher.js"
|
|
18
13
|
import { defaultRuntimeCompat } from "@jsenv/core/src/build/build.js"
|
|
19
|
-
import { createReloadableWorker } from "@jsenv/core/src/helpers/worker_reload.js"
|
|
20
14
|
import { createFileService } from "./file_service.js"
|
|
21
15
|
|
|
22
16
|
/**
|
|
@@ -24,39 +18,30 @@ import { createFileService } from "./file_service.js"
|
|
|
24
18
|
* - cook source files according to jsenv plugins
|
|
25
19
|
* - inject code to autoreload the browser when a file is modified
|
|
26
20
|
* @param {Object} devServerParameters
|
|
27
|
-
* @param {string|url} devServerParameters.
|
|
21
|
+
* @param {string|url} devServerParameters.sourceDirectoryUrl Root directory of the project
|
|
28
22
|
* @return {Object} A dev server object
|
|
29
23
|
*/
|
|
30
24
|
export const startDevServer = async ({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
sourceDirectoryUrl,
|
|
26
|
+
sourceMainFilePath,
|
|
27
|
+
port = 3456,
|
|
28
|
+
hostname,
|
|
29
|
+
acceptAnyIp,
|
|
35
30
|
https,
|
|
36
31
|
// it's better to use http1 by default because it allows to get statusText in devtools
|
|
37
32
|
// which gives valuable information when there is errors
|
|
38
33
|
http2 = false,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
acceptAnyIp,
|
|
42
|
-
keepProcessAlive = true,
|
|
34
|
+
logLevel = process.env.IMPORTED_BY_TEST_PLAN ? "warn" : "info",
|
|
35
|
+
serverLogLevel = "warn",
|
|
43
36
|
services = [],
|
|
37
|
+
|
|
38
|
+
signal = new AbortController().signal,
|
|
39
|
+
handleSIGINT = true,
|
|
40
|
+
keepProcessAlive = true,
|
|
44
41
|
onStop = () => {},
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
clientFiles = {
|
|
48
|
-
"./src/": true,
|
|
49
|
-
"./tests/": true,
|
|
50
|
-
"./package.json": true,
|
|
51
|
-
},
|
|
52
|
-
devServerFiles = {
|
|
53
|
-
"./package.json": true,
|
|
54
|
-
"./jsenv.config.mjs": true,
|
|
55
|
-
},
|
|
43
|
+
sourceFilesConfig,
|
|
56
44
|
clientAutoreload = true,
|
|
57
|
-
clientMainFileUrl,
|
|
58
|
-
devServerAutoreload = false,
|
|
59
|
-
devServerMainFile = getCallerPosition().url,
|
|
60
45
|
cooldownBetweenFileEvents,
|
|
61
46
|
|
|
62
47
|
// runtimeCompat is the runtimeCompat for the build
|
|
@@ -90,13 +75,10 @@ export const startDevServer = async ({
|
|
|
90
75
|
`${unexpectedParamNames.join(",")}: there is no such param`,
|
|
91
76
|
)
|
|
92
77
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
rootDirectoryUrl = rootDirectoryUrlValidation.value
|
|
78
|
+
sourceDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
79
|
+
sourceDirectoryUrl,
|
|
80
|
+
"sourceDirectoryUrl",
|
|
81
|
+
)
|
|
100
82
|
}
|
|
101
83
|
|
|
102
84
|
const logger = createLogger({ logLevel })
|
|
@@ -112,58 +94,6 @@ export const startDevServer = async ({
|
|
|
112
94
|
)
|
|
113
95
|
})
|
|
114
96
|
}
|
|
115
|
-
|
|
116
|
-
let reloadableWorker
|
|
117
|
-
if (devServerAutoreload) {
|
|
118
|
-
reloadableWorker = createReloadableWorker(devServerMainFile)
|
|
119
|
-
if (reloadableWorker.isPrimary) {
|
|
120
|
-
const devServerFileChangeCallback = ({ relativeUrl, event }) => {
|
|
121
|
-
const url = new URL(relativeUrl, rootDirectoryUrl).href
|
|
122
|
-
logger.info(`file ${event} ${url} -> restarting server...`)
|
|
123
|
-
reloadableWorker.reload()
|
|
124
|
-
}
|
|
125
|
-
const stopWatchingDevServerFiles = registerDirectoryLifecycle(
|
|
126
|
-
rootDirectoryUrl,
|
|
127
|
-
{
|
|
128
|
-
watchPatterns: {
|
|
129
|
-
...devServerFiles.include,
|
|
130
|
-
[devServerMainFile]: true,
|
|
131
|
-
".jsenv/": false,
|
|
132
|
-
},
|
|
133
|
-
cooldownBetweenFileEvents,
|
|
134
|
-
keepProcessAlive: false,
|
|
135
|
-
recursive: true,
|
|
136
|
-
added: ({ relativeUrl }) => {
|
|
137
|
-
devServerFileChangeCallback({ relativeUrl, event: "added" })
|
|
138
|
-
},
|
|
139
|
-
updated: ({ relativeUrl }) => {
|
|
140
|
-
devServerFileChangeCallback({ relativeUrl, event: "modified" })
|
|
141
|
-
},
|
|
142
|
-
removed: ({ relativeUrl }) => {
|
|
143
|
-
devServerFileChangeCallback({ relativeUrl, event: "removed" })
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
)
|
|
147
|
-
operation.addAbortCallback(() => {
|
|
148
|
-
stopWatchingDevServerFiles()
|
|
149
|
-
reloadableWorker.terminate()
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
const worker = await reloadableWorker.load()
|
|
153
|
-
const messagePromise = new Promise((resolve) => {
|
|
154
|
-
worker.once("message", resolve)
|
|
155
|
-
})
|
|
156
|
-
const origin = await messagePromise
|
|
157
|
-
return {
|
|
158
|
-
origin,
|
|
159
|
-
stop: () => {
|
|
160
|
-
stopWatchingDevServerFiles()
|
|
161
|
-
reloadableWorker.terminate()
|
|
162
|
-
},
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
97
|
const startDevServerTask = createTaskLog("start dev server", {
|
|
168
98
|
disabled: !logger.levels.info,
|
|
169
99
|
})
|
|
@@ -201,6 +131,28 @@ export const startDevServer = async ({
|
|
|
201
131
|
accessControlAllowCredentials: true,
|
|
202
132
|
timingAllowOrigin: true,
|
|
203
133
|
}),
|
|
134
|
+
{
|
|
135
|
+
handleRequest: (request) => {
|
|
136
|
+
if (request.pathname === "/__server_params__.json") {
|
|
137
|
+
const json = JSON.stringify({
|
|
138
|
+
sourceDirectoryUrl,
|
|
139
|
+
})
|
|
140
|
+
return {
|
|
141
|
+
status: 200,
|
|
142
|
+
headers: {
|
|
143
|
+
"content-type": "application/json",
|
|
144
|
+
"content-length": Buffer.byteLength(json),
|
|
145
|
+
},
|
|
146
|
+
body: json,
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (request.pathname === "/__stop__") {
|
|
150
|
+
server.stop()
|
|
151
|
+
return { status: 200 }
|
|
152
|
+
}
|
|
153
|
+
return null
|
|
154
|
+
},
|
|
155
|
+
},
|
|
204
156
|
...services,
|
|
205
157
|
{
|
|
206
158
|
name: "jsenv:omega_file_service",
|
|
@@ -211,7 +163,9 @@ export const startDevServer = async ({
|
|
|
211
163
|
serverEventsDispatcher,
|
|
212
164
|
contextCache,
|
|
213
165
|
|
|
214
|
-
|
|
166
|
+
sourceDirectoryUrl,
|
|
167
|
+
sourceMainFilePath,
|
|
168
|
+
sourceFilesConfig,
|
|
215
169
|
runtimeCompat,
|
|
216
170
|
|
|
217
171
|
plugins,
|
|
@@ -221,8 +175,6 @@ export const startDevServer = async ({
|
|
|
221
175
|
supervisor,
|
|
222
176
|
transpilation,
|
|
223
177
|
clientAutoreload,
|
|
224
|
-
clientFiles,
|
|
225
|
-
clientMainFileUrl,
|
|
226
178
|
cooldownBetweenFileEvents,
|
|
227
179
|
explorer,
|
|
228
180
|
cacheControl,
|
|
@@ -298,9 +250,6 @@ export const startDevServer = async ({
|
|
|
298
250
|
logger.info(`- ${server.origins[key]}`)
|
|
299
251
|
})
|
|
300
252
|
logger.info(``)
|
|
301
|
-
if (reloadableWorker && reloadableWorker.isWorker) {
|
|
302
|
-
parentPort.postMessage(server.origin)
|
|
303
|
-
}
|
|
304
253
|
return {
|
|
305
254
|
origin: server.origin,
|
|
306
255
|
stop: () => {
|
package/src/execute/execute.js
CHANGED
|
@@ -39,7 +39,10 @@ export const execute = async ({
|
|
|
39
39
|
ignoreError = false,
|
|
40
40
|
}) => {
|
|
41
41
|
const logger = createLogger({ logLevel })
|
|
42
|
-
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
42
|
+
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
43
|
+
rootDirectoryUrl,
|
|
44
|
+
"rootDirectoryUrl",
|
|
45
|
+
)
|
|
43
46
|
const executeOperation = Abort.startOperation()
|
|
44
47
|
executeOperation.addAbortSignal(signal)
|
|
45
48
|
if (handleSIGINT) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { basename } from "node:path"
|
|
2
|
+
|
|
3
|
+
import { lookupPackageDirectory } from "./lookup_package_directory.js"
|
|
4
|
+
|
|
5
|
+
export const determineJsenvInternalDirectoryUrl = (currentUrl) => {
|
|
6
|
+
const packageDirectoryUrl = lookupPackageDirectory(currentUrl)
|
|
7
|
+
if (packageDirectoryUrl) {
|
|
8
|
+
return `${packageDirectoryUrl}.jsenv/${getDirectoryName(
|
|
9
|
+
packageDirectoryUrl,
|
|
10
|
+
)}/`
|
|
11
|
+
}
|
|
12
|
+
return `${currentUrl}.jsenv/`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const getDirectoryName = (directoryUrl) => {
|
|
16
|
+
const { pathname } = new URL(directoryUrl)
|
|
17
|
+
return basename(pathname)
|
|
18
|
+
}
|
package/src/kitchen/kitchen.js
CHANGED
|
@@ -28,6 +28,7 @@ export const createKitchen = ({
|
|
|
28
28
|
logLevel,
|
|
29
29
|
|
|
30
30
|
rootDirectoryUrl,
|
|
31
|
+
jsenvInternalDirectoryUrl,
|
|
31
32
|
urlGraph,
|
|
32
33
|
dev = false,
|
|
33
34
|
build = false,
|
|
@@ -50,6 +51,7 @@ export const createKitchen = ({
|
|
|
50
51
|
signal,
|
|
51
52
|
logger,
|
|
52
53
|
rootDirectoryUrl,
|
|
54
|
+
jsenvInternalDirectoryUrl,
|
|
53
55
|
urlGraph,
|
|
54
56
|
dev,
|
|
55
57
|
build,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
|
|
3
|
+
export const lookupPackageDirectory = (currentUrl) => {
|
|
4
|
+
if (currentUrl === "file:///") {
|
|
5
|
+
return null
|
|
6
|
+
}
|
|
7
|
+
const packageJsonFileUrl = `${currentUrl}package.json`
|
|
8
|
+
if (existsSync(new URL(packageJsonFileUrl))) {
|
|
9
|
+
return currentUrl
|
|
10
|
+
}
|
|
11
|
+
return lookupPackageDirectory(getParentUrl(currentUrl))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const getParentUrl = (url) => {
|
|
15
|
+
if (url.startsWith("file://")) {
|
|
16
|
+
// With node.js new URL('../', 'file:///C:/').href
|
|
17
|
+
// returns "file:///C:/" instead of "file:///"
|
|
18
|
+
const resource = url.slice("file://".length)
|
|
19
|
+
const slashLastIndex = resource.lastIndexOf("/")
|
|
20
|
+
if (slashLastIndex === -1) {
|
|
21
|
+
return url
|
|
22
|
+
}
|
|
23
|
+
const lastCharIndex = resource.length - 1
|
|
24
|
+
if (slashLastIndex === lastCharIndex) {
|
|
25
|
+
const slashBeforeLastIndex = resource.lastIndexOf("/", slashLastIndex - 1)
|
|
26
|
+
if (slashBeforeLastIndex === -1) {
|
|
27
|
+
return url
|
|
28
|
+
}
|
|
29
|
+
return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`
|
|
30
|
+
}
|
|
31
|
+
return `file://${resource.slice(0, slashLastIndex + 1)}`
|
|
32
|
+
}
|
|
33
|
+
return new URL(url.endsWith("/") ? "../" : "./", url).href
|
|
34
|
+
}
|
|
@@ -11,13 +11,14 @@ export const explorerHtmlFileUrl = new URL(
|
|
|
11
11
|
export const jsenvPluginExplorer = ({
|
|
12
12
|
groups = {
|
|
13
13
|
src: {
|
|
14
|
-
"
|
|
14
|
+
"./**/*.html": true,
|
|
15
|
+
"./**/*.test.html": false,
|
|
15
16
|
},
|
|
16
17
|
tests: {
|
|
17
|
-
"
|
|
18
|
+
"./**/*.test.html": true,
|
|
18
19
|
},
|
|
19
20
|
},
|
|
20
|
-
|
|
21
|
+
mainFileUrl,
|
|
21
22
|
}) => {
|
|
22
23
|
const faviconClientFileUrl = new URL("./client/jsenv.png", import.meta.url)
|
|
23
24
|
|
|
@@ -26,7 +27,7 @@ export const jsenvPluginExplorer = ({
|
|
|
26
27
|
appliesDuring: "dev",
|
|
27
28
|
transformUrlContent: {
|
|
28
29
|
html: async (urlInfo, context) => {
|
|
29
|
-
if (urlInfo.url !==
|
|
30
|
+
if (urlInfo.url !== mainFileUrl) {
|
|
30
31
|
return null
|
|
31
32
|
}
|
|
32
33
|
let html = urlInfo.content
|
package/src/plugins/plugins.js
CHANGED
|
@@ -16,15 +16,13 @@ import { jsenvPluginImportMetaHot } from "./import_meta_hot/jsenv_plugin_import_
|
|
|
16
16
|
import { jsenvPluginAutoreload } from "./autoreload/jsenv_plugin_autoreload.js"
|
|
17
17
|
import { jsenvPluginCacheControl } from "./cache_control/jsenv_plugin_cache_control.js"
|
|
18
18
|
// dev only
|
|
19
|
-
import {
|
|
20
|
-
explorerHtmlFileUrl,
|
|
21
|
-
jsenvPluginExplorer,
|
|
22
|
-
} from "./explorer/jsenv_plugin_explorer.js"
|
|
19
|
+
import { jsenvPluginExplorer } from "./explorer/jsenv_plugin_explorer.js"
|
|
23
20
|
// other
|
|
24
21
|
import { jsenvPluginRibbon } from "./ribbon/jsenv_plugin_ribbon.js"
|
|
25
22
|
|
|
26
23
|
export const getCorePlugins = ({
|
|
27
24
|
rootDirectoryUrl,
|
|
25
|
+
mainFileUrl,
|
|
28
26
|
runtimeCompat,
|
|
29
27
|
|
|
30
28
|
urlAnalysis = {},
|
|
@@ -34,7 +32,6 @@ export const getCorePlugins = ({
|
|
|
34
32
|
supervisor,
|
|
35
33
|
transpilation = true,
|
|
36
34
|
|
|
37
|
-
clientMainFileUrl,
|
|
38
35
|
clientAutoreload = false,
|
|
39
36
|
clientFileChangeCallbackList,
|
|
40
37
|
clientFilesPruneCallbackList,
|
|
@@ -58,13 +55,6 @@ export const getCorePlugins = ({
|
|
|
58
55
|
if (clientAutoreload === true) {
|
|
59
56
|
clientAutoreload = {}
|
|
60
57
|
}
|
|
61
|
-
if (clientMainFileUrl === undefined) {
|
|
62
|
-
clientMainFileUrl = explorer
|
|
63
|
-
? String(explorerHtmlFileUrl)
|
|
64
|
-
: String(new URL("./index.html", rootDirectoryUrl))
|
|
65
|
-
} else {
|
|
66
|
-
clientMainFileUrl = String(clientMainFileUrl)
|
|
67
|
-
}
|
|
68
58
|
|
|
69
59
|
if (ribbon === true) {
|
|
70
60
|
ribbon = {}
|
|
@@ -85,7 +75,7 @@ export const getCorePlugins = ({
|
|
|
85
75
|
jsenvPluginHttpUrls(),
|
|
86
76
|
jsenvPluginUrlResolution({
|
|
87
77
|
runtimeCompat,
|
|
88
|
-
|
|
78
|
+
mainFileUrl,
|
|
89
79
|
urlResolution,
|
|
90
80
|
}),
|
|
91
81
|
jsenvPluginUrlVersion(),
|
|
@@ -106,9 +96,7 @@ export const getCorePlugins = ({
|
|
|
106
96
|
]
|
|
107
97
|
: []),
|
|
108
98
|
...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []),
|
|
109
|
-
...(explorer
|
|
110
|
-
? [jsenvPluginExplorer({ ...explorer, clientMainFileUrl })]
|
|
111
|
-
: []),
|
|
99
|
+
...(explorer ? [jsenvPluginExplorer({ ...explorer, mainFileUrl })] : []),
|
|
112
100
|
...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
|
|
113
101
|
]
|
|
114
102
|
}
|
|
@@ -32,7 +32,7 @@ import { createNodeEsmResolver } from "./node_esm_resolver.js"
|
|
|
32
32
|
|
|
33
33
|
export const jsenvPluginUrlResolution = ({
|
|
34
34
|
runtimeCompat,
|
|
35
|
-
|
|
35
|
+
mainFileUrl,
|
|
36
36
|
urlResolution,
|
|
37
37
|
}) => {
|
|
38
38
|
const resolveUrlUsingWebResolution = (reference) => {
|
|
@@ -97,7 +97,7 @@ export const jsenvPluginUrlResolution = ({
|
|
|
97
97
|
appliesDuring: "*",
|
|
98
98
|
resolveUrl: (reference, context) => {
|
|
99
99
|
if (reference.specifier === "/") {
|
|
100
|
-
return String(
|
|
100
|
+
return String(mainFileUrl)
|
|
101
101
|
}
|
|
102
102
|
if (reference.specifier[0] === "/") {
|
|
103
103
|
return new URL(reference.specifier.slice(1), context.rootDirectoryUrl)
|
|
@@ -33,8 +33,10 @@ export const readNodeV8CoverageDirectory = async ({
|
|
|
33
33
|
operation.throwIfAborted()
|
|
34
34
|
const dirContent = await tryReadDirectory()
|
|
35
35
|
|
|
36
|
-
const coverageDirectoryUrl =
|
|
37
|
-
|
|
36
|
+
const coverageDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
37
|
+
NODE_V8_COVERAGE,
|
|
38
|
+
"NODE_V8_COVERAGE",
|
|
39
|
+
)
|
|
38
40
|
|
|
39
41
|
await dirContent.reduce(async (previous, dirEntry) => {
|
|
40
42
|
operation.throwIfAborted()
|