@jsenv/core 27.8.0 → 28.0.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 +2 -2
- package/dist/js/html_supervisor_installer.js +3 -3
- package/dist/js/server_events_client.js +1 -1
- package/dist/main.js +520 -469
- package/package.json +2 -2
- package/readme.md +1 -1
- package/src/build/build.js +8 -8
- package/src/build/{resync_ressource_hints.js → resync_resource_hints.js} +10 -12
- package/src/build/start_build_server.js +6 -9
- package/src/dev/start_dev_server.js +2 -2
- package/src/execute/execute.js +14 -52
- package/src/execute/runtimes/browsers/from_playwright.js +19 -8
- package/src/main.js +3 -0
- package/src/omega/kitchen.js +5 -5
- package/src/omega/omega_server.js +2 -2
- package/src/omega/server/file_service.js +3 -3
- package/src/omega/url_graph/url_graph_load.js +4 -4
- package/src/omega/url_graph.js +3 -3
- package/src/ping_server.js +30 -0
- package/src/plugins/autoreload/client/reload.js +2 -2
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -1
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +3 -3
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +1 -1
- package/src/plugins/explorer/jsenv_plugin_explorer.js +1 -1
- package/src/plugins/html_supervisor/client/error_formatter.js +3 -3
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +5 -5
- package/src/plugins/import_meta_hot/html_hot_dependencies.js +4 -4
- package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +1 -9
- package/src/plugins/plugin_controller.js +2 -2
- package/src/plugins/server_events/client/server_events_client.js +1 -1
- package/src/plugins/toolbar/jsenv_plugin_toolbar.js +1 -1
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +2 -2
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +3 -3
- package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +13 -0
- package/src/plugins/url_analysis/html/html_urls.js +2 -2
- package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +1 -1
- package/src/test/execute_plan.js +15 -68
- package/src/test/execute_test_plan.js +4 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "28.0.1",
|
|
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": "
|
|
76
|
+
"@jsenv/server": "14.1.0",
|
|
77
77
|
"@jsenv/sourcemap": "1.0.4",
|
|
78
78
|
"@jsenv/uneval": "1.6.0",
|
|
79
79
|
"@jsenv/url-meta": "7.0.0",
|
package/readme.md
CHANGED
|
@@ -16,7 +16,7 @@ npm create jsenv@latest
|
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
This command prompts to choose a demo from a list.
|
|
19
|
-
Each demo contains preconfigured scripts
|
|
19
|
+
Each demo contains preconfigured scripts:
|
|
20
20
|
|
|
21
21
|
- `npm run dev`: starts a dev server with autoreload.
|
|
22
22
|
- `npm run test`: execute test files on browsers(s) and/or Node.js.
|
package/src/build/build.js
CHANGED
|
@@ -45,7 +45,7 @@ import { createBuilUrlsGenerator } from "./build_urls_generator.js"
|
|
|
45
45
|
import { injectGlobalVersionMapping } from "./inject_global_version_mappings.js"
|
|
46
46
|
import { createVersionGenerator } from "./version_generator.js"
|
|
47
47
|
import { injectServiceWorkerUrls } from "./inject_service_worker_urls.js"
|
|
48
|
-
import {
|
|
48
|
+
import { resyncResourceHints } from "./resync_resource_hints.js"
|
|
49
49
|
|
|
50
50
|
// default runtimeCompat corresponds to
|
|
51
51
|
// "we can keep <script type="module"> intact":
|
|
@@ -314,13 +314,13 @@ build ${entryPointKeys.length} entry points`)
|
|
|
314
314
|
})
|
|
315
315
|
rawUrlInfo.references.forEach((reference) => {
|
|
316
316
|
if (
|
|
317
|
-
reference.
|
|
317
|
+
reference.isResourceHint &&
|
|
318
318
|
reference.expectedType === "js_module"
|
|
319
319
|
) {
|
|
320
320
|
const referencedUrlInfo = rawGraph.getUrlInfo(reference.url)
|
|
321
321
|
if (
|
|
322
322
|
referencedUrlInfo &&
|
|
323
|
-
// something else than the
|
|
323
|
+
// something else than the resource hint is using this url
|
|
324
324
|
referencedUrlInfo.dependents.size > 0
|
|
325
325
|
) {
|
|
326
326
|
addToBundlerIfAny(referencedUrlInfo)
|
|
@@ -611,7 +611,7 @@ build ${entryPointKeys.length} entry points`)
|
|
|
611
611
|
`urls should be inside build directory at this stage, found "${reference.url}"`,
|
|
612
612
|
)
|
|
613
613
|
}
|
|
614
|
-
if (reference.
|
|
614
|
+
if (reference.isResourceHint) {
|
|
615
615
|
// return the raw url, we will resync at the end
|
|
616
616
|
return rawUrls[reference.url]
|
|
617
617
|
}
|
|
@@ -717,7 +717,7 @@ build ${entryPointKeys.length} entry points`)
|
|
|
717
717
|
kitchen: finalGraphKitchen,
|
|
718
718
|
outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
|
|
719
719
|
writeGeneratedFiles,
|
|
720
|
-
|
|
720
|
+
skipResourceHint: true,
|
|
721
721
|
startLoading: (cookEntryFile) => {
|
|
722
722
|
entryUrls.forEach((entryUrl) => {
|
|
723
723
|
const [, postBuildEntryUrlInfo] = cookEntryFile({
|
|
@@ -786,7 +786,7 @@ ${Array.from(finalGraph.urlInfoMap.keys()).join("\n")}`,
|
|
|
786
786
|
urlInfo.data.buildUrlIsVersioned = useVersionedUrl
|
|
787
787
|
urlInfo.data.buildUrlSpecifier = buildUrlSpecifier
|
|
788
788
|
})
|
|
789
|
-
await
|
|
789
|
+
await resyncResourceHints({
|
|
790
790
|
logger,
|
|
791
791
|
finalGraphKitchen,
|
|
792
792
|
finalGraph,
|
|
@@ -1116,7 +1116,7 @@ const applyUrlVersioning = async ({
|
|
|
1116
1116
|
if (reference.isInline || reference.url.startsWith("data:")) {
|
|
1117
1117
|
return null
|
|
1118
1118
|
}
|
|
1119
|
-
if (reference.
|
|
1119
|
+
if (reference.isResourceHint) {
|
|
1120
1120
|
return null
|
|
1121
1121
|
}
|
|
1122
1122
|
// specifier comes from "normalize" hook done a bit earlier in this file
|
|
@@ -1185,7 +1185,7 @@ const applyUrlVersioning = async ({
|
|
|
1185
1185
|
operation: buildOperation,
|
|
1186
1186
|
urlGraph: finalGraph,
|
|
1187
1187
|
kitchen: versioningKitchen,
|
|
1188
|
-
|
|
1188
|
+
skipResourceHint: true,
|
|
1189
1189
|
writeGeneratedFiles,
|
|
1190
1190
|
startLoading: (cookEntryFile) => {
|
|
1191
1191
|
postBuildEntryUrls.forEach((postBuildEntryUrl) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Update <link rel="preload"> and friends after build (once we know everything)
|
|
3
3
|
*
|
|
4
|
-
* - Used to remove
|
|
4
|
+
* - Used to remove resource hint targeting an url that is no longer used:
|
|
5
5
|
* - Happens because of import assertions transpilation (file is inlined into JS)
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -16,19 +16,19 @@ import {
|
|
|
16
16
|
|
|
17
17
|
import { GRAPH } from "./graph_utils.js"
|
|
18
18
|
|
|
19
|
-
export const
|
|
19
|
+
export const resyncResourceHints = async ({
|
|
20
20
|
logger,
|
|
21
21
|
finalGraphKitchen,
|
|
22
22
|
finalGraph,
|
|
23
23
|
rawUrls,
|
|
24
24
|
postBuildRedirections,
|
|
25
25
|
}) => {
|
|
26
|
-
const
|
|
26
|
+
const resourceHintActions = []
|
|
27
27
|
GRAPH.forEach(finalGraph, (urlInfo) => {
|
|
28
28
|
if (urlInfo.type !== "html") {
|
|
29
29
|
return
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
resourceHintActions.push(async () => {
|
|
32
32
|
const htmlAst = parseHtmlString(urlInfo.content, {
|
|
33
33
|
storeOriginalPositions: false,
|
|
34
34
|
})
|
|
@@ -38,14 +38,14 @@ export const resyncRessourceHints = async ({
|
|
|
38
38
|
return
|
|
39
39
|
}
|
|
40
40
|
const rel = getHtmlNodeAttribute(linkNode, "rel")
|
|
41
|
-
const
|
|
41
|
+
const isresourceHint = [
|
|
42
42
|
"preconnect",
|
|
43
43
|
"dns-prefetch",
|
|
44
44
|
"prefetch",
|
|
45
45
|
"preload",
|
|
46
46
|
"modulepreload",
|
|
47
47
|
].includes(rel)
|
|
48
|
-
if (!
|
|
48
|
+
if (!isresourceHint) {
|
|
49
49
|
return
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -57,7 +57,7 @@ export const resyncRessourceHints = async ({
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
if (!buildUrl) {
|
|
60
|
-
logger.warn(`remove
|
|
60
|
+
logger.warn(`remove resource hint because cannot find "${href}"`)
|
|
61
61
|
actions.push(() => {
|
|
62
62
|
removeHtmlNode(linkNode)
|
|
63
63
|
})
|
|
@@ -67,7 +67,7 @@ export const resyncRessourceHints = async ({
|
|
|
67
67
|
const urlInfo = finalGraph.getUrlInfo(buildUrl)
|
|
68
68
|
if (!urlInfo) {
|
|
69
69
|
logger.warn(
|
|
70
|
-
`remove
|
|
70
|
+
`remove resource hint because cannot find "${buildUrl}" in the graph`,
|
|
71
71
|
)
|
|
72
72
|
actions.push(() => {
|
|
73
73
|
removeHtmlNode(linkNode)
|
|
@@ -75,9 +75,7 @@ export const resyncRessourceHints = async ({
|
|
|
75
75
|
return
|
|
76
76
|
}
|
|
77
77
|
if (urlInfo.dependents.size === 0) {
|
|
78
|
-
logger.info(
|
|
79
|
-
`remove ressource hint because "${href}" not used anymore`,
|
|
80
|
-
)
|
|
78
|
+
logger.info(`remove resource hint because "${href}" not used anymore`)
|
|
81
79
|
actions.push(() => {
|
|
82
80
|
removeHtmlNode(linkNode)
|
|
83
81
|
})
|
|
@@ -109,6 +107,6 @@ export const resyncRessourceHints = async ({
|
|
|
109
107
|
})
|
|
110
108
|
})
|
|
111
109
|
await Promise.all(
|
|
112
|
-
|
|
110
|
+
resourceHintActions.map((resourceHintAction) => resourceHintAction()),
|
|
113
111
|
)
|
|
114
112
|
}
|
|
@@ -41,7 +41,7 @@ export const startBuildServer = async ({
|
|
|
41
41
|
certificate,
|
|
42
42
|
privateKey,
|
|
43
43
|
acceptAnyIp,
|
|
44
|
-
|
|
44
|
+
hostname,
|
|
45
45
|
port = 9779,
|
|
46
46
|
services = [],
|
|
47
47
|
keepProcessAlive = true,
|
|
@@ -163,7 +163,7 @@ export const startBuildServer = async ({
|
|
|
163
163
|
certificate,
|
|
164
164
|
privateKey,
|
|
165
165
|
acceptAnyIp,
|
|
166
|
-
|
|
166
|
+
hostname,
|
|
167
167
|
port,
|
|
168
168
|
serverTiming: true,
|
|
169
169
|
requestWaitingMs: 60_000,
|
|
@@ -208,18 +208,15 @@ export const startBuildServer = async ({
|
|
|
208
208
|
|
|
209
209
|
const createBuildFilesService = ({ buildDirectoryUrl, buildIndexPath }) => {
|
|
210
210
|
return (request) => {
|
|
211
|
-
const urlIsVersioned = new URL(
|
|
212
|
-
|
|
213
|
-
request.origin,
|
|
214
|
-
).searchParams.has("v")
|
|
215
|
-
if (buildIndexPath && request.ressource === "/") {
|
|
211
|
+
const urlIsVersioned = new URL(request.url).searchParams.has("v")
|
|
212
|
+
if (buildIndexPath && request.resource === "/") {
|
|
216
213
|
request = {
|
|
217
214
|
...request,
|
|
218
|
-
|
|
215
|
+
resource: `/${buildIndexPath}`,
|
|
219
216
|
}
|
|
220
217
|
}
|
|
221
218
|
return fetchFileSystem(
|
|
222
|
-
new URL(request.
|
|
219
|
+
new URL(request.resource.slice(1), buildDirectoryUrl),
|
|
223
220
|
{
|
|
224
221
|
headers: request.headers,
|
|
225
222
|
cacheControl: urlIsVersioned
|
|
@@ -22,7 +22,7 @@ export const startDevServer = async ({
|
|
|
22
22
|
http2 = false,
|
|
23
23
|
certificate,
|
|
24
24
|
privateKey,
|
|
25
|
-
|
|
25
|
+
hostname,
|
|
26
26
|
port = 3456,
|
|
27
27
|
acceptAnyIp,
|
|
28
28
|
keepProcessAlive = true,
|
|
@@ -150,7 +150,7 @@ export const startDevServer = async ({
|
|
|
150
150
|
http2,
|
|
151
151
|
certificate,
|
|
152
152
|
privateKey,
|
|
153
|
-
|
|
153
|
+
hostname,
|
|
154
154
|
port,
|
|
155
155
|
services,
|
|
156
156
|
|
package/src/execute/execute.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
|
|
2
|
-
|
|
3
2
|
import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
4
3
|
import { createLogger } from "@jsenv/log"
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import { pingServer } from "../ping_server.js"
|
|
7
6
|
import { run } from "./run.js"
|
|
8
7
|
|
|
9
8
|
export const execute = async ({
|
|
@@ -11,12 +10,13 @@ export const execute = async ({
|
|
|
11
10
|
handleSIGINT = true,
|
|
12
11
|
logLevel,
|
|
13
12
|
rootDirectoryUrl,
|
|
13
|
+
devServerOrigin,
|
|
14
14
|
|
|
15
15
|
fileRelativeUrl,
|
|
16
16
|
allocatedMs,
|
|
17
17
|
mirrorConsole = true,
|
|
18
18
|
keepRunning = false,
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
collectConsole,
|
|
21
21
|
collectCoverage,
|
|
22
22
|
coverageTempDirectoryUrl,
|
|
@@ -24,21 +24,6 @@ export const execute = async ({
|
|
|
24
24
|
runtime,
|
|
25
25
|
runtimeParams,
|
|
26
26
|
|
|
27
|
-
scenarios = { dev: true },
|
|
28
|
-
plugins = [],
|
|
29
|
-
nodeEsmResolution,
|
|
30
|
-
fileSystemMagicResolution,
|
|
31
|
-
transpilation,
|
|
32
|
-
htmlSupervisor = true,
|
|
33
|
-
sourcemaps = "inline",
|
|
34
|
-
writeGeneratedFiles = false,
|
|
35
|
-
|
|
36
|
-
port,
|
|
37
|
-
protocol,
|
|
38
|
-
http2,
|
|
39
|
-
certificate,
|
|
40
|
-
privateKey,
|
|
41
|
-
|
|
42
27
|
ignoreError = false,
|
|
43
28
|
}) => {
|
|
44
29
|
const logger = createLogger({ logLevel })
|
|
@@ -59,44 +44,21 @@ export const execute = async ({
|
|
|
59
44
|
let resultTransformer = (result) => result
|
|
60
45
|
runtimeParams = {
|
|
61
46
|
rootDirectoryUrl,
|
|
47
|
+
devServerOrigin,
|
|
62
48
|
fileRelativeUrl,
|
|
63
49
|
...runtimeParams,
|
|
64
50
|
}
|
|
65
|
-
if (runtime.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
services,
|
|
71
|
-
port,
|
|
72
|
-
protocol,
|
|
73
|
-
http2,
|
|
74
|
-
certificate,
|
|
75
|
-
privateKey,
|
|
76
|
-
|
|
77
|
-
rootDirectoryUrl,
|
|
78
|
-
scenarios,
|
|
79
|
-
runtimeCompat: { [runtime.name]: runtime.version },
|
|
80
|
-
|
|
81
|
-
plugins,
|
|
82
|
-
|
|
83
|
-
htmlSupervisor,
|
|
84
|
-
nodeEsmResolution,
|
|
85
|
-
fileSystemMagicResolution,
|
|
86
|
-
transpilation,
|
|
87
|
-
sourcemaps,
|
|
88
|
-
writeGeneratedFiles,
|
|
89
|
-
})
|
|
90
|
-
executeOperation.addEndCallback(async () => {
|
|
91
|
-
await server.stop("execution done")
|
|
92
|
-
})
|
|
93
|
-
runtimeParams = {
|
|
94
|
-
...runtimeParams,
|
|
95
|
-
server,
|
|
51
|
+
if (runtime.type === "browser") {
|
|
52
|
+
if (!devServerOrigin) {
|
|
53
|
+
throw new TypeError(
|
|
54
|
+
`devServerOrigin is required when running tests on browser(s)`,
|
|
55
|
+
)
|
|
96
56
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
57
|
+
const devServerStarted = await pingServer(devServerOrigin)
|
|
58
|
+
if (!devServerStarted) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`dev server not started at ${devServerOrigin}. It is required to run tests`,
|
|
61
|
+
)
|
|
100
62
|
}
|
|
101
63
|
}
|
|
102
64
|
|
|
@@ -27,7 +27,6 @@ export const createRuntimeFromPlaywright = ({
|
|
|
27
27
|
type: "browser",
|
|
28
28
|
name: browserName,
|
|
29
29
|
version: browserVersion,
|
|
30
|
-
needsServer: true,
|
|
31
30
|
}
|
|
32
31
|
let browserAndContextPromise
|
|
33
32
|
runtime.run = async ({
|
|
@@ -35,7 +34,7 @@ export const createRuntimeFromPlaywright = ({
|
|
|
35
34
|
logger,
|
|
36
35
|
rootDirectoryUrl,
|
|
37
36
|
fileRelativeUrl,
|
|
38
|
-
|
|
37
|
+
devServerOrigin,
|
|
39
38
|
|
|
40
39
|
// measurePerformance,
|
|
41
40
|
collectPerformance,
|
|
@@ -98,7 +97,19 @@ export const createRuntimeFromPlaywright = ({
|
|
|
98
97
|
}
|
|
99
98
|
await disconnected
|
|
100
99
|
}
|
|
101
|
-
const
|
|
100
|
+
const coverageInHeaders =
|
|
101
|
+
coverageEnabled &&
|
|
102
|
+
(!coveragePlaywrightAPIAvailable ||
|
|
103
|
+
coverageMethodForBrowsers !== "playwright_api")
|
|
104
|
+
const page = await browserContext.newPage({
|
|
105
|
+
extraHTTPHeaders: {
|
|
106
|
+
...(coverageInHeaders
|
|
107
|
+
? {
|
|
108
|
+
"x-coverage-istanbul": JSON.stringify(coverageConfig),
|
|
109
|
+
}
|
|
110
|
+
: {}),
|
|
111
|
+
},
|
|
112
|
+
})
|
|
102
113
|
const closePage = async () => {
|
|
103
114
|
try {
|
|
104
115
|
await page.close()
|
|
@@ -128,7 +139,7 @@ export const createRuntimeFromPlaywright = ({
|
|
|
128
139
|
(v8CoveragesWithWebUrl) => {
|
|
129
140
|
const fsUrl = moveUrl({
|
|
130
141
|
url: v8CoveragesWithWebUrl.url,
|
|
131
|
-
from: `${
|
|
142
|
+
from: `${devServerOrigin}/`,
|
|
132
143
|
to: rootDirectoryUrl,
|
|
133
144
|
preferAbsolute: true,
|
|
134
145
|
})
|
|
@@ -202,7 +213,7 @@ export const createRuntimeFromPlaywright = ({
|
|
|
202
213
|
})
|
|
203
214
|
}
|
|
204
215
|
|
|
205
|
-
const fileClientUrl = new URL(fileRelativeUrl, `${
|
|
216
|
+
const fileClientUrl = new URL(fileRelativeUrl, `${devServerOrigin}/`).href
|
|
206
217
|
|
|
207
218
|
// https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
|
|
208
219
|
const removeConsoleListener = registerEvent({
|
|
@@ -302,7 +313,7 @@ export const createRuntimeFromPlaywright = ({
|
|
|
302
313
|
const { exceptionSource } = returnValue
|
|
303
314
|
const error = evalException(exceptionSource, {
|
|
304
315
|
rootDirectoryUrl,
|
|
305
|
-
|
|
316
|
+
devServerOrigin,
|
|
306
317
|
transformErrorHook,
|
|
307
318
|
})
|
|
308
319
|
cb({
|
|
@@ -525,13 +536,13 @@ const registerEvent = ({ object, eventType, callback }) => {
|
|
|
525
536
|
|
|
526
537
|
const evalException = (
|
|
527
538
|
exceptionSource,
|
|
528
|
-
{ rootDirectoryUrl,
|
|
539
|
+
{ rootDirectoryUrl, devServerOrigin, transformErrorHook },
|
|
529
540
|
) => {
|
|
530
541
|
const script = new Script(exceptionSource, { filename: "" })
|
|
531
542
|
const error = script.runInThisContext()
|
|
532
543
|
if (error && error instanceof Error) {
|
|
533
544
|
const remoteRootRegexp = new RegExp(
|
|
534
|
-
escapeRegexpSpecialChars(`${
|
|
545
|
+
escapeRegexpSpecialChars(`${devServerOrigin}/`),
|
|
535
546
|
"g",
|
|
536
547
|
)
|
|
537
548
|
error.stack = error.stack.replace(remoteRootRegexp, rootDirectoryUrl)
|
package/src/main.js
CHANGED
|
@@ -21,6 +21,9 @@ export { nodeWorkerThread } from "./execute/runtimes/node/node_worker_thread.js"
|
|
|
21
21
|
export { build } from "./build/build.js"
|
|
22
22
|
export { startBuildServer } from "./build/start_build_server.js"
|
|
23
23
|
|
|
24
|
+
// helpers
|
|
25
|
+
export { pingServer } from "./ping_server.js"
|
|
26
|
+
|
|
24
27
|
// advanced
|
|
25
28
|
export { execute } from "./execute/execute.js"
|
|
26
29
|
export { jsenvPluginInjectGlobals } from "./plugins/inject_globals/jsenv_plugin_inject_globals.js"
|
package/src/omega/kitchen.js
CHANGED
|
@@ -88,7 +88,7 @@ export const createKitchen = ({
|
|
|
88
88
|
isEntryPoint = false,
|
|
89
89
|
isInline = false,
|
|
90
90
|
injected = false,
|
|
91
|
-
|
|
91
|
+
isResourceHint = false,
|
|
92
92
|
content,
|
|
93
93
|
contentType,
|
|
94
94
|
assert,
|
|
@@ -125,8 +125,8 @@ export const createKitchen = ({
|
|
|
125
125
|
isEntryPoint,
|
|
126
126
|
isInline,
|
|
127
127
|
injected,
|
|
128
|
-
|
|
129
|
-
// for inline
|
|
128
|
+
isResourceHint,
|
|
129
|
+
// for inline resources the reference contains the content
|
|
130
130
|
content,
|
|
131
131
|
contentType,
|
|
132
132
|
timing: {},
|
|
@@ -182,8 +182,8 @@ export const createKitchen = ({
|
|
|
182
182
|
// And this is because this hook inject query params used to:
|
|
183
183
|
// - bypass browser cache (?v)
|
|
184
184
|
// - convey information (?hmr)
|
|
185
|
-
// But do not represent an other
|
|
186
|
-
// the same
|
|
185
|
+
// But do not represent an other resource, it is considered as
|
|
186
|
+
// the same resource under the hood
|
|
187
187
|
pluginController.callHooks(
|
|
188
188
|
"transformUrlSearchParams",
|
|
189
189
|
reference,
|
|
@@ -18,7 +18,7 @@ export const startOmegaServer = async ({
|
|
|
18
18
|
privateKey,
|
|
19
19
|
certificate,
|
|
20
20
|
acceptAnyIp,
|
|
21
|
-
|
|
21
|
+
hostname,
|
|
22
22
|
port = 0,
|
|
23
23
|
keepProcessAlive = false,
|
|
24
24
|
onStop = () => {},
|
|
@@ -62,7 +62,7 @@ export const startOmegaServer = async ({
|
|
|
62
62
|
certificate,
|
|
63
63
|
privateKey,
|
|
64
64
|
acceptAnyIp,
|
|
65
|
-
|
|
65
|
+
hostname,
|
|
66
66
|
port,
|
|
67
67
|
requestWaitingMs: 60_1000,
|
|
68
68
|
services: [
|
|
@@ -185,7 +185,7 @@ export const createFileService = ({
|
|
|
185
185
|
|
|
186
186
|
return async (request) => {
|
|
187
187
|
// serve file inside ".jsenv" directory
|
|
188
|
-
const requestFileUrl = new URL(request.
|
|
188
|
+
const requestFileUrl = new URL(request.resource.slice(1), rootDirectoryUrl)
|
|
189
189
|
.href
|
|
190
190
|
if (urlIsInsideOf(requestFileUrl, jsenvDirectoryUrl)) {
|
|
191
191
|
return fetchFileSystem(requestFileUrl, {
|
|
@@ -206,14 +206,14 @@ export const createFileService = ({
|
|
|
206
206
|
let reference
|
|
207
207
|
const parentUrl = inferParentFromRequest(request, rootDirectoryUrl)
|
|
208
208
|
if (parentUrl) {
|
|
209
|
-
reference = urlGraph.inferReference(request.
|
|
209
|
+
reference = urlGraph.inferReference(request.resource, parentUrl)
|
|
210
210
|
}
|
|
211
211
|
if (!reference) {
|
|
212
212
|
const entryPoint = kitchen.injectReference({
|
|
213
213
|
trace: { message: parentUrl || rootDirectoryUrl },
|
|
214
214
|
parentUrl: parentUrl || rootDirectoryUrl,
|
|
215
215
|
type: "http_request",
|
|
216
|
-
specifier: request.
|
|
216
|
+
specifier: request.resource,
|
|
217
217
|
})
|
|
218
218
|
reference = entryPoint[0]
|
|
219
219
|
}
|
|
@@ -31,11 +31,11 @@ export const loadUrlGraph = async ({
|
|
|
31
31
|
})
|
|
32
32
|
const { references } = urlInfo
|
|
33
33
|
references.forEach((reference) => {
|
|
34
|
-
// we don't cook
|
|
35
|
-
// because they might refer to
|
|
34
|
+
// we don't cook resource hints
|
|
35
|
+
// because they might refer to resource that will be modified during build
|
|
36
36
|
// It also means something else have to reference that url in order to cook it
|
|
37
|
-
// so that the preload is deleted by "
|
|
38
|
-
if (reference.
|
|
37
|
+
// so that the preload is deleted by "resync_resource_hints.js" otherwise
|
|
38
|
+
if (reference.isResourceHint) {
|
|
39
39
|
return
|
|
40
40
|
}
|
|
41
41
|
// we use reference.generatedUrl to mimic what a browser would do:
|
package/src/omega/url_graph.js
CHANGED
|
@@ -70,10 +70,10 @@ export const createUrlGraph = ({
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
references.forEach((reference) => {
|
|
73
|
-
if (reference.
|
|
74
|
-
//
|
|
73
|
+
if (reference.isResourceHint) {
|
|
74
|
+
// resource hint are a special kind of reference.
|
|
75
75
|
// They are a sort of weak reference to an url.
|
|
76
|
-
// We ignore them so that url referenced only by
|
|
76
|
+
// We ignore them so that url referenced only by resource hints
|
|
77
77
|
// have url.dependents.size === 0 and can be considered as not used
|
|
78
78
|
// It means html won't consider url referenced solely
|
|
79
79
|
// by <link> as dependency and it's fine
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createServer } from "node:net"
|
|
2
|
+
|
|
3
|
+
export const pingServer = async (url) => {
|
|
4
|
+
const server = createServer()
|
|
5
|
+
const { hostname, port } = new URL(url)
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
await new Promise((resolve, reject) => {
|
|
9
|
+
server.on("error", reject)
|
|
10
|
+
server.on("listening", () => {
|
|
11
|
+
resolve()
|
|
12
|
+
})
|
|
13
|
+
server.listen(port, hostname)
|
|
14
|
+
})
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error && error.code === "EADDRINUSE") {
|
|
17
|
+
return true
|
|
18
|
+
}
|
|
19
|
+
if (error && error.code === "EACCES") {
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
throw error
|
|
23
|
+
}
|
|
24
|
+
await new Promise((resolve, reject) => {
|
|
25
|
+
server.on("error", reject)
|
|
26
|
+
server.on("close", resolve)
|
|
27
|
+
server.close()
|
|
28
|
+
})
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
@@ -62,8 +62,8 @@ export const getDOMNodesUsingUrl = (urlToReload) => {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
})
|
|
65
|
-
// There is no real need to update a.href because the
|
|
66
|
-
// But in a scenario where the
|
|
65
|
+
// There is no real need to update a.href because the resource will be fetched when clicked.
|
|
66
|
+
// But in a scenario where the resource was already visited and is in browser cache, adding
|
|
67
67
|
// the dynamic query param ensure the cache is invalidated
|
|
68
68
|
Array.from(document.querySelectorAll("a")).forEach((a) => {
|
|
69
69
|
visitNodeAttributeAsUrl(a, "href")
|
|
@@ -13,7 +13,7 @@ export const jsenvPluginAutoreloadClient = () => {
|
|
|
13
13
|
|
|
14
14
|
return {
|
|
15
15
|
name: "jsenv:autoreload_client",
|
|
16
|
-
appliesDuring:
|
|
16
|
+
appliesDuring: "dev",
|
|
17
17
|
transformUrlContent: {
|
|
18
18
|
html: (htmlUrlInfo, context) => {
|
|
19
19
|
const htmlAst = parseHtmlString(htmlUrlInfo.content)
|
|
@@ -6,7 +6,7 @@ export const jsenvPluginAutoreloadServer = ({
|
|
|
6
6
|
}) => {
|
|
7
7
|
return {
|
|
8
8
|
name: "jsenv:autoreload_server",
|
|
9
|
-
appliesDuring:
|
|
9
|
+
appliesDuring: "dev",
|
|
10
10
|
serverEvents: {
|
|
11
11
|
reload: ({ sendServerEvent, rootDirectoryUrl, urlGraph }) => {
|
|
12
12
|
const formatUrlForClient = (url) => {
|
|
@@ -140,7 +140,7 @@ export const jsenvPluginAutoreloadServer = ({
|
|
|
140
140
|
const cause = `following files are no longer referenced: ${prunedUrlInfos.map(
|
|
141
141
|
(prunedUrlInfo) => formatUrlForClient(prunedUrlInfo.url),
|
|
142
142
|
)}`
|
|
143
|
-
// now check if we can hot update the main
|
|
143
|
+
// now check if we can hot update the main resource
|
|
144
144
|
// then if we can hot update all dependencies
|
|
145
145
|
if (mainHotUpdate.declined) {
|
|
146
146
|
notifyDeclined({
|
|
@@ -179,7 +179,7 @@ export const jsenvPluginAutoreloadServer = ({
|
|
|
179
179
|
},
|
|
180
180
|
},
|
|
181
181
|
serve: (request, { rootDirectoryUrl, urlGraph }) => {
|
|
182
|
-
if (request.
|
|
182
|
+
if (request.pathname === "/__graph__") {
|
|
183
183
|
const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl))
|
|
184
184
|
return {
|
|
185
185
|
status: 200,
|
|
@@ -11,7 +11,7 @@ export const jsenvPluginExplorer = ({ groups }) => {
|
|
|
11
11
|
name: "jsenv:explorer",
|
|
12
12
|
appliesDuring: "dev",
|
|
13
13
|
serve: async (request, { rootDirectoryUrl }) => {
|
|
14
|
-
if (request.
|
|
14
|
+
if (request.pathname !== "/") {
|
|
15
15
|
return null
|
|
16
16
|
}
|
|
17
17
|
const associationsForExplorable = {}
|
|
@@ -154,13 +154,13 @@ export const formatError = (
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
if (urlSite.line !== undefined) {
|
|
157
|
-
let
|
|
157
|
+
let resourceToFetch = `/__get_code_frame__/${formatUrlWithLineAndColumn(
|
|
158
158
|
urlSite,
|
|
159
159
|
)}`
|
|
160
160
|
if (!Error.captureStackTrace) {
|
|
161
|
-
|
|
161
|
+
resourceToFetch += `?remap`
|
|
162
162
|
}
|
|
163
|
-
const response = await window.fetch(
|
|
163
|
+
const response = await window.fetch(resourceToFetch)
|
|
164
164
|
const codeFrame = await response.text()
|
|
165
165
|
return {
|
|
166
166
|
codeFrame: formatErrorText({ message: codeFrame }),
|