@jsenv/core 39.14.3 → 40.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/directory_listing.js +16 -9
- package/dist/js/server_events_client.js +2 -2
- package/dist/jsenv_core.js +7220 -11089
- package/package.json +22 -19
- package/src/build/build.js +122 -93
- package/src/build/build_specifier_manager.js +103 -94
- package/src/build/build_urls_generator.js +1 -1
- package/src/build/{version_mappings_injection.js → mappings_injection.js} +62 -21
- package/src/build/start_build_server.js +46 -36
- package/src/dev/start_dev_server.js +246 -248
- package/src/helpers/watch_source_files.js +50 -36
- package/src/kitchen/fetched_content_compliance.js +4 -2
- package/src/kitchen/kitchen.js +31 -24
- package/src/kitchen/url_graph/references.js +10 -2
- package/src/kitchen/url_graph/url_graph.js +3 -0
- package/src/kitchen/url_graph/url_graph_visitor.js +3 -0
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +29 -16
- package/src/plugins/html_syntax_error_fallback/jsenv_plugin_html_syntax_error_fallback.js +1 -1
- package/src/plugins/plugin_controller.js +194 -200
- package/src/plugins/plugins.js +5 -0
- package/src/plugins/protocol_file/client/directory_listing.jsx +5 -0
- package/src/plugins/protocol_file/jsenv_plugin_directory_listing.js +92 -67
- package/src/plugins/protocol_file/jsenv_plugin_fs_redirection.js +17 -7
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +6 -0
- package/src/plugins/protocol_http/jsenv_plugin_protocol_http.js +33 -3
- package/src/plugins/reference_analysis/html/jsenv_plugin_html_reference_analysis.js +15 -22
- package/src/plugins/reference_analysis/js/jsenv_plugin_js_reference_analysis.js +53 -2
- package/src/plugins/resolution_node_esm/jsenv_plugin_node_esm_resolution.js +37 -30
- package/src/plugins/resolution_node_esm/node_esm_resolver.js +4 -8
- package/src/plugins/resolution_web/jsenv_plugin_web_resolution.js +8 -6
- package/src/plugins/server_events/client/server_events_client.js +2 -2
- package/src/plugins/server_events/jsenv_plugin_server_events.js +18 -16
- package/dist/js/ws.js +0 -6863
- package/src/helpers/lookup_package_directory.js +0 -9
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
import {
|
|
26
26
|
comparePathnames,
|
|
27
|
+
lookupPackageDirectory,
|
|
27
28
|
readEntryStatSync,
|
|
28
29
|
registerDirectoryLifecycle,
|
|
29
30
|
} from "@jsenv/filesystem";
|
|
30
|
-
import { pickContentType } from "@jsenv/server";
|
|
31
|
+
import { pickContentType, WebSocketResponse } from "@jsenv/server";
|
|
31
32
|
import {
|
|
32
33
|
asUrlWithoutSearch,
|
|
33
34
|
ensurePathnameTrailingSlash,
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
urlToRelativeUrl,
|
|
37
38
|
} from "@jsenv/urls";
|
|
38
39
|
import { existsSync, lstatSync, readdirSync } from "node:fs";
|
|
39
|
-
import {
|
|
40
|
+
import { getDirectoryWatchPatterns } from "../../helpers/watch_source_files.js";
|
|
40
41
|
import { replacePlaceholders } from "../injections/jsenv_plugin_injections.js";
|
|
41
42
|
import { FILE_AND_SERVER_URLS_CONVERTER } from "./file_and_server_urls_converter.js";
|
|
42
43
|
|
|
@@ -49,6 +50,9 @@ export const jsenvPluginDirectoryListing = ({
|
|
|
49
50
|
urlMocks = false,
|
|
50
51
|
autoreload = true,
|
|
51
52
|
directoryContentMagicName,
|
|
53
|
+
rootDirectoryUrl,
|
|
54
|
+
mainFilePath,
|
|
55
|
+
sourceFilesConfig,
|
|
52
56
|
}) => {
|
|
53
57
|
return {
|
|
54
58
|
name: "jsenv:directory_listing",
|
|
@@ -66,16 +70,24 @@ export const jsenvPluginDirectoryListing = ({
|
|
|
66
70
|
fsStat = readEntryStatSync(url, { nullIfNotFound: true });
|
|
67
71
|
reference.fsStat = fsStat;
|
|
68
72
|
}
|
|
69
|
-
const { request, requestedUrl } =
|
|
73
|
+
const { request, requestedUrl, mainFilePath, rootDirectoryUrl } =
|
|
74
|
+
reference.ownerUrlInfo.context;
|
|
70
75
|
if (!fsStat) {
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
request &&
|
|
74
|
-
request.headers["sec-fetch-dest"] === "document"
|
|
75
|
-
) {
|
|
76
|
-
return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(url)}&enoent`;
|
|
76
|
+
if (!request || request.headers["sec-fetch-dest"] !== "document") {
|
|
77
|
+
return null;
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
+
if (url !== requestedUrl) {
|
|
80
|
+
const mainFileUrl = new URL(mainFilePath, rootDirectoryUrl);
|
|
81
|
+
mainFileUrl.search = "";
|
|
82
|
+
mainFileUrl.hash = "";
|
|
83
|
+
const referenceUrl = new URL(url);
|
|
84
|
+
referenceUrl.search = "";
|
|
85
|
+
referenceUrl.hash = "";
|
|
86
|
+
if (mainFileUrl.href !== referenceUrl.href) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(url)}&enoent`;
|
|
79
91
|
}
|
|
80
92
|
const isDirectory = fsStat?.isDirectory();
|
|
81
93
|
if (!isDirectory) {
|
|
@@ -130,65 +142,78 @@ export const jsenvPluginDirectoryListing = ({
|
|
|
130
142
|
);
|
|
131
143
|
},
|
|
132
144
|
},
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
145
|
+
devServerRoutes: [
|
|
146
|
+
{
|
|
147
|
+
endpoint:
|
|
148
|
+
"GET /.internal/directory_content.websocket?directory=:directory",
|
|
149
|
+
description: "Emit events when a directory content changes.",
|
|
150
|
+
declarationSource: import.meta.url,
|
|
151
|
+
fetch: (request) => {
|
|
152
|
+
if (!autoreload) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return new WebSocketResponse((websocket) => {
|
|
156
|
+
const directoryRelativeUrl = request.params.directory;
|
|
157
|
+
const requestedUrl = FILE_AND_SERVER_URLS_CONVERTER.asFileUrl(
|
|
158
|
+
directoryRelativeUrl,
|
|
159
|
+
rootDirectoryUrl,
|
|
160
|
+
);
|
|
161
|
+
const closestDirectoryUrl =
|
|
162
|
+
getFirstExistingDirectoryUrl(requestedUrl);
|
|
163
|
+
const sendMessage = (message) => {
|
|
164
|
+
websocket.send(JSON.stringify(message));
|
|
165
|
+
};
|
|
166
|
+
const generateItems = () => {
|
|
167
|
+
const firstExistingDirectoryUrl = getFirstExistingDirectoryUrl(
|
|
168
|
+
requestedUrl,
|
|
169
|
+
rootDirectoryUrl,
|
|
170
|
+
);
|
|
171
|
+
const items = getDirectoryContentItems({
|
|
172
|
+
serverRootDirectoryUrl: rootDirectoryUrl,
|
|
173
|
+
mainFilePath,
|
|
174
|
+
requestedUrl,
|
|
175
|
+
firstExistingDirectoryUrl,
|
|
176
|
+
});
|
|
177
|
+
return items;
|
|
178
|
+
};
|
|
163
179
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
180
|
+
const unwatch = registerDirectoryLifecycle(closestDirectoryUrl, {
|
|
181
|
+
added: ({ relativeUrl }) => {
|
|
182
|
+
sendMessage({
|
|
183
|
+
type: "change",
|
|
184
|
+
reason: `${relativeUrl} added`,
|
|
185
|
+
items: generateItems(),
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
updated: ({ relativeUrl }) => {
|
|
189
|
+
sendMessage({
|
|
190
|
+
type: "change",
|
|
191
|
+
reason: `${relativeUrl} updated`,
|
|
192
|
+
items: generateItems(),
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
removed: ({ relativeUrl }) => {
|
|
196
|
+
sendMessage({
|
|
197
|
+
type: "change",
|
|
198
|
+
reason: `${relativeUrl} removed`,
|
|
199
|
+
items: generateItems(),
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
watchPatterns: getDirectoryWatchPatterns(
|
|
203
|
+
closestDirectoryUrl,
|
|
204
|
+
closestDirectoryUrl,
|
|
205
|
+
{
|
|
206
|
+
sourceFilesConfig,
|
|
207
|
+
},
|
|
208
|
+
),
|
|
209
|
+
});
|
|
210
|
+
return () => {
|
|
211
|
+
unwatch();
|
|
212
|
+
};
|
|
170
213
|
});
|
|
171
214
|
},
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
type: "change",
|
|
175
|
-
reason: `${relativeUrl} updated`,
|
|
176
|
-
items: generateItems(),
|
|
177
|
-
});
|
|
178
|
-
},
|
|
179
|
-
removed: ({ relativeUrl }) => {
|
|
180
|
-
sendMessage({
|
|
181
|
-
type: "change",
|
|
182
|
-
reason: `${relativeUrl} removed`,
|
|
183
|
-
items: generateItems(),
|
|
184
|
-
});
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
websocket.signal.addEventListener("abort", () => {
|
|
188
|
-
unwatch();
|
|
189
|
-
});
|
|
190
|
-
return true;
|
|
191
|
-
},
|
|
215
|
+
},
|
|
216
|
+
],
|
|
192
217
|
};
|
|
193
218
|
};
|
|
194
219
|
|
|
@@ -257,7 +282,7 @@ const generateDirectoryListingInjection = (
|
|
|
257
282
|
);
|
|
258
283
|
const websocketScheme = request.protocol === "https" ? "wss" : "ws";
|
|
259
284
|
const { host } = new URL(request.url);
|
|
260
|
-
const websocketUrl = `${websocketScheme}://${host}
|
|
285
|
+
const websocketUrl = `${websocketScheme}://${host}/.internal/directory_content.websocket?directory=${encodeURIComponent(directoryUrlRelativeToServer)}`;
|
|
261
286
|
|
|
262
287
|
const navItems = [];
|
|
263
288
|
nav_items: {
|
|
@@ -17,20 +17,30 @@ export const jsenvPluginFsRedirection = ({
|
|
|
17
17
|
name: "jsenv:fs_redirection",
|
|
18
18
|
appliesDuring: "*",
|
|
19
19
|
redirectReference: (reference) => {
|
|
20
|
+
if (reference.url === "file:///") {
|
|
21
|
+
return `ignore:file:///`;
|
|
22
|
+
}
|
|
23
|
+
if (reference.url === "file://") {
|
|
24
|
+
return `ignore:file://`;
|
|
25
|
+
}
|
|
26
|
+
// ignore all new URL second arg
|
|
27
|
+
if (reference.subtype === "new_url_second_arg") {
|
|
28
|
+
if (reference.original) {
|
|
29
|
+
return `ignore:${reference.original.specifier}`;
|
|
30
|
+
}
|
|
31
|
+
return `ignore:${reference.specifier}`;
|
|
32
|
+
}
|
|
20
33
|
// http, https, data, about, ...
|
|
21
34
|
if (!reference.url.startsWith("file:")) {
|
|
22
35
|
return null;
|
|
23
36
|
}
|
|
24
|
-
if (reference.
|
|
37
|
+
if (reference.original && !reference.original.url.startsWith("file:")) {
|
|
25
38
|
return null;
|
|
26
39
|
}
|
|
27
|
-
if (reference.
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
// ignore all new URL second arg
|
|
31
|
-
if (reference.subtype === "new_url_second_arg") {
|
|
32
|
-
return `ignore:${reference.url}`;
|
|
40
|
+
if (reference.isInline) {
|
|
41
|
+
return null;
|
|
33
42
|
}
|
|
43
|
+
|
|
34
44
|
if (
|
|
35
45
|
reference.specifierPathname.endsWith(`/${directoryContentMagicName}`)
|
|
36
46
|
) {
|
|
@@ -13,6 +13,9 @@ export const jsenvPluginProtocolFile = ({
|
|
|
13
13
|
magicDirectoryIndex,
|
|
14
14
|
preserveSymlinks,
|
|
15
15
|
directoryListing,
|
|
16
|
+
rootDirectoryUrl,
|
|
17
|
+
mainFilePath,
|
|
18
|
+
sourceFilesConfig,
|
|
16
19
|
}) => {
|
|
17
20
|
return [
|
|
18
21
|
jsenvPluginFsRedirection({
|
|
@@ -73,6 +76,9 @@ export const jsenvPluginProtocolFile = ({
|
|
|
73
76
|
jsenvPluginDirectoryListing({
|
|
74
77
|
...directoryListing,
|
|
75
78
|
directoryContentMagicName,
|
|
79
|
+
rootDirectoryUrl,
|
|
80
|
+
mainFilePath,
|
|
81
|
+
sourceFilesConfig,
|
|
76
82
|
}),
|
|
77
83
|
]
|
|
78
84
|
: []),
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { URL_META } from "@jsenv/url-meta";
|
|
2
|
+
import { setUrlExtension, urlToExtension, urlToFilename } from "@jsenv/urls";
|
|
2
3
|
import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
|
|
3
4
|
|
|
4
5
|
export const jsenvPluginProtocolHttp = ({ include }) => {
|
|
6
|
+
const prependIgnore = (reference) => {
|
|
7
|
+
if (reference.original) {
|
|
8
|
+
return `ignore:${reference.original.specifier}`;
|
|
9
|
+
}
|
|
10
|
+
return `ignore:${reference.specifier}`;
|
|
11
|
+
};
|
|
12
|
+
|
|
5
13
|
if (include === false) {
|
|
6
14
|
return {
|
|
7
15
|
name: "jsenv:protocol_http",
|
|
@@ -10,7 +18,7 @@ export const jsenvPluginProtocolHttp = ({ include }) => {
|
|
|
10
18
|
if (!reference.url.startsWith("http")) {
|
|
11
19
|
return null;
|
|
12
20
|
}
|
|
13
|
-
return
|
|
21
|
+
return prependIgnore(reference);
|
|
14
22
|
},
|
|
15
23
|
};
|
|
16
24
|
}
|
|
@@ -33,7 +41,7 @@ export const jsenvPluginProtocolHttp = ({ include }) => {
|
|
|
33
41
|
return null;
|
|
34
42
|
}
|
|
35
43
|
if (!shouldInclude(reference.url)) {
|
|
36
|
-
return
|
|
44
|
+
return prependIgnore(reference);
|
|
37
45
|
}
|
|
38
46
|
const outDirectoryUrl = reference.ownerUrlInfo.context.outDirectoryUrl;
|
|
39
47
|
const urlObject = new URL(reference.url);
|
|
@@ -72,12 +80,34 @@ export const jsenvPluginProtocolHttp = ({ include }) => {
|
|
|
72
80
|
if (isTextual) {
|
|
73
81
|
content = await response.text();
|
|
74
82
|
} else {
|
|
75
|
-
content = await response.
|
|
83
|
+
content = Buffer.from(await response.arrayBuffer());
|
|
76
84
|
}
|
|
85
|
+
// When fetching content from http it's possible to request something like
|
|
86
|
+
// "https://esm.sh/preact@10.23.1
|
|
87
|
+
// and receive content-type "application/javascript"
|
|
88
|
+
// if we do nothing, after build there will be a "preact@10.23.1" file without ".js" extension
|
|
89
|
+
// and the build server will serve this as "application/octet-stream".
|
|
90
|
+
// We want to build files to be compatible with any server and keep build server logic simple.
|
|
91
|
+
// -> We auto-append the extension corresponding to the content-type
|
|
92
|
+
let filenameHint;
|
|
93
|
+
const extension = urlToExtension(originalUrl);
|
|
94
|
+
if (extension === "") {
|
|
95
|
+
const wellKnownExtensionForThisContentType =
|
|
96
|
+
CONTENT_TYPE.toUrlExtension(contentType);
|
|
97
|
+
if (wellKnownExtensionForThisContentType) {
|
|
98
|
+
const urlWithExtension = setUrlExtension(
|
|
99
|
+
originalUrl,
|
|
100
|
+
wellKnownExtensionForThisContentType,
|
|
101
|
+
);
|
|
102
|
+
filenameHint = urlToFilename(urlWithExtension);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
77
106
|
return {
|
|
78
107
|
content,
|
|
79
108
|
contentType,
|
|
80
109
|
contentLength: responseHeaders.get("content-length") || undefined,
|
|
110
|
+
filenameHint,
|
|
81
111
|
};
|
|
82
112
|
},
|
|
83
113
|
};
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
getUrlForContentInsideHtml,
|
|
8
8
|
parseHtml,
|
|
9
9
|
parseSrcSet,
|
|
10
|
-
removeHtmlNode,
|
|
11
10
|
removeHtmlNodeText,
|
|
12
11
|
setHtmlNodeAttributes,
|
|
13
12
|
setHtmlNodeText,
|
|
@@ -63,22 +62,25 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
63
62
|
// no importmap in this HTML file
|
|
64
63
|
importmaps[htmlUrl] = null;
|
|
65
64
|
}
|
|
66
|
-
|
|
65
|
+
let importmapFinal = null;
|
|
66
|
+
for (const url of Object.keys(importmaps)) {
|
|
67
67
|
const importmap = importmaps[url];
|
|
68
|
-
if (!previous) {
|
|
69
|
-
return importmap;
|
|
70
|
-
}
|
|
71
68
|
if (!importmap) {
|
|
72
|
-
|
|
69
|
+
continue;
|
|
73
70
|
}
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
if (!importmapFinal) {
|
|
72
|
+
importmapFinal = importmap;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
importmapFinal = composeTwoImportMaps(importmapFinal, importmap);
|
|
76
|
+
}
|
|
77
|
+
globalImportmap = importmapFinal;
|
|
76
78
|
|
|
77
79
|
importmapLoadingCount--;
|
|
78
80
|
if (importmapLoadingCount === 0) {
|
|
79
|
-
allImportmapLoadedCallbackSet
|
|
80
|
-
|
|
81
|
-
}
|
|
81
|
+
for (const allImportmapLoadedCallback of allImportmapLoadedCallbackSet) {
|
|
82
|
+
allImportmapLoadedCallback();
|
|
83
|
+
}
|
|
82
84
|
allImportmapLoadedCallbackSet.clear();
|
|
83
85
|
}
|
|
84
86
|
};
|
|
@@ -103,6 +105,7 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
103
105
|
},
|
|
104
106
|
});
|
|
105
107
|
if (fromMapping) {
|
|
108
|
+
reference.data.fromMapping = true;
|
|
106
109
|
return result;
|
|
107
110
|
}
|
|
108
111
|
return null;
|
|
@@ -433,7 +436,7 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
433
436
|
setHtmlNodeAttributes(scriptNode, {
|
|
434
437
|
"src": undefined,
|
|
435
438
|
"jsenv-inlined-by": "jsenv:html_reference_analysis",
|
|
436
|
-
"inlined-from-src":
|
|
439
|
+
"inlined-from-src": importmapReference.url,
|
|
437
440
|
});
|
|
438
441
|
});
|
|
439
442
|
});
|
|
@@ -471,16 +474,6 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
471
474
|
});
|
|
472
475
|
}
|
|
473
476
|
}
|
|
474
|
-
// once this plugin knows the importmap, it will use it
|
|
475
|
-
// to map imports. These import specifiers will be normalized
|
|
476
|
-
// by "formatReference" making the importmap presence useless.
|
|
477
|
-
// In dev/test we keep importmap into the HTML to see it even if useless
|
|
478
|
-
// Duing build we get rid of it
|
|
479
|
-
if (urlInfo.context.build) {
|
|
480
|
-
mutations.push(() => {
|
|
481
|
-
removeHtmlNode(scriptNode);
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
477
|
return;
|
|
485
478
|
}
|
|
486
479
|
const externalRef = visitSrc(scriptNode, {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { getUrlForContentInsideJs, parseJsUrls } from "@jsenv/ast";
|
|
2
|
+
import {
|
|
3
|
+
isWebWorkerEntryPointReference,
|
|
4
|
+
isWebWorkerUrlInfo,
|
|
5
|
+
} from "@jsenv/core/src/kitchen/web_workers.js";
|
|
2
6
|
import { createMagicSource } from "@jsenv/sourcemap";
|
|
3
7
|
import { urlToExtension } from "@jsenv/urls";
|
|
4
8
|
import { JS_QUOTES } from "@jsenv/utils/src/string/js_quotes.js";
|
|
5
9
|
|
|
6
|
-
import { isWebWorkerUrlInfo } from "@jsenv/core/src/kitchen/web_workers.js";
|
|
7
|
-
|
|
8
10
|
export const jsenvPluginJsReferenceAnalysis = ({ inlineContent }) => {
|
|
9
11
|
return [
|
|
10
12
|
{
|
|
@@ -97,6 +99,34 @@ const parseAndTransformJsReferences = async (
|
|
|
97
99
|
) {
|
|
98
100
|
externalReferenceInfo.expectedType = "js_module";
|
|
99
101
|
}
|
|
102
|
+
|
|
103
|
+
let filenameHint;
|
|
104
|
+
if (
|
|
105
|
+
externalReferenceInfo.subtype === "import_dynamic" &&
|
|
106
|
+
isBareSpecifier(externalReferenceInfo.specifier)
|
|
107
|
+
) {
|
|
108
|
+
filenameHint = `${externalReferenceInfo.specifier}.js`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let isEntryPoint;
|
|
112
|
+
let isDynamicEntryPoint;
|
|
113
|
+
if (
|
|
114
|
+
isNodeJs &&
|
|
115
|
+
(externalReferenceInfo.type === "js_url" ||
|
|
116
|
+
externalReferenceInfo.subtype === "import_meta_resolve")
|
|
117
|
+
) {
|
|
118
|
+
isEntryPoint = true;
|
|
119
|
+
isDynamicEntryPoint = true;
|
|
120
|
+
} else if (
|
|
121
|
+
isWebWorkerEntryPointReference({
|
|
122
|
+
subtype: externalReferenceInfo.subtype,
|
|
123
|
+
expectedSubtype: externalReferenceInfo.expectedSubtype,
|
|
124
|
+
})
|
|
125
|
+
) {
|
|
126
|
+
isEntryPoint = true;
|
|
127
|
+
} else {
|
|
128
|
+
isEntryPoint = false;
|
|
129
|
+
}
|
|
100
130
|
const reference = urlInfo.dependencies.found({
|
|
101
131
|
type: externalReferenceInfo.type,
|
|
102
132
|
subtype: externalReferenceInfo.subtype,
|
|
@@ -119,7 +149,11 @@ const parseAndTransformJsReferences = async (
|
|
|
119
149
|
importAttributes: externalReferenceInfo.importAttributes,
|
|
120
150
|
isSideEffectImport: externalReferenceInfo.isSideEffectImport,
|
|
121
151
|
astInfo: externalReferenceInfo.astInfo,
|
|
152
|
+
isEntryPoint,
|
|
153
|
+
isDynamicEntryPoint,
|
|
154
|
+
filenameHint,
|
|
122
155
|
});
|
|
156
|
+
|
|
123
157
|
parallelActions.push(async () => {
|
|
124
158
|
await reference.readGeneratedSpecifier();
|
|
125
159
|
const replacement = reference.generatedSpecifier;
|
|
@@ -158,3 +192,20 @@ const parseAndTransformJsReferences = async (
|
|
|
158
192
|
const { content, sourcemap } = magicSource.toContentAndSourcemap();
|
|
159
193
|
return { content, sourcemap };
|
|
160
194
|
};
|
|
195
|
+
|
|
196
|
+
const isBareSpecifier = (specifier) => {
|
|
197
|
+
if (
|
|
198
|
+
specifier[0] === "/" ||
|
|
199
|
+
specifier.startsWith("./") ||
|
|
200
|
+
specifier.startsWith("../")
|
|
201
|
+
) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
// eslint-disable-next-line no-new
|
|
206
|
+
new URL(specifier);
|
|
207
|
+
return false;
|
|
208
|
+
} catch {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
@@ -3,43 +3,50 @@ import { createNodeEsmResolver } from "./node_esm_resolver.js";
|
|
|
3
3
|
export const jsenvPluginNodeEsmResolution = (resolutionConfig = {}) => {
|
|
4
4
|
let nodeEsmResolverDefault;
|
|
5
5
|
const resolvers = {};
|
|
6
|
-
Object.keys(resolutionConfig).forEach((urlType) => {
|
|
7
|
-
const config = resolutionConfig[urlType];
|
|
8
|
-
if (config === true) {
|
|
9
|
-
resolvers[urlType] = (...args) => nodeEsmResolverDefault(...args);
|
|
10
|
-
} else if (config === false) {
|
|
11
|
-
resolvers[urlType] = () => null;
|
|
12
|
-
} else if (typeof config === "object") {
|
|
13
|
-
const { runtimeCompat, packageConditions, preservesSymlink, ...rest } =
|
|
14
|
-
config;
|
|
15
|
-
const unexpectedKeys = Object.keys(rest);
|
|
16
|
-
if (unexpectedKeys.length) {
|
|
17
|
-
throw new TypeError(
|
|
18
|
-
`${unexpectedKeys.join(
|
|
19
|
-
",",
|
|
20
|
-
)}: there is no such configuration on "${urlType}"`,
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
resolvers[urlType] = createNodeEsmResolver({
|
|
24
|
-
runtimeCompat,
|
|
25
|
-
packageConditions,
|
|
26
|
-
preservesSymlink,
|
|
27
|
-
});
|
|
28
|
-
} else {
|
|
29
|
-
throw new TypeError(
|
|
30
|
-
`config must be true, false or an object, got ${config} on "${urlType}"`,
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
6
|
|
|
35
7
|
return {
|
|
36
8
|
name: "jsenv:node_esm_resolution",
|
|
37
9
|
appliesDuring: "*",
|
|
38
|
-
init: (
|
|
10
|
+
init: (kitchenContext) => {
|
|
39
11
|
nodeEsmResolverDefault = createNodeEsmResolver({
|
|
40
|
-
|
|
12
|
+
build: kitchenContext.build,
|
|
13
|
+
runtimeCompat: kitchenContext.runtimeCompat,
|
|
41
14
|
preservesSymlink: true,
|
|
42
15
|
});
|
|
16
|
+
Object.keys(resolutionConfig).forEach((urlType) => {
|
|
17
|
+
const config = resolutionConfig[urlType];
|
|
18
|
+
if (config === true) {
|
|
19
|
+
resolvers[urlType] = (...args) => nodeEsmResolverDefault(...args);
|
|
20
|
+
} else if (config === false) {
|
|
21
|
+
resolvers[urlType] = () => null;
|
|
22
|
+
} else if (typeof config === "object") {
|
|
23
|
+
const {
|
|
24
|
+
runtimeCompat,
|
|
25
|
+
packageConditions,
|
|
26
|
+
preservesSymlink,
|
|
27
|
+
...rest
|
|
28
|
+
} = config;
|
|
29
|
+
const unexpectedKeys = Object.keys(rest);
|
|
30
|
+
if (unexpectedKeys.length) {
|
|
31
|
+
throw new TypeError(
|
|
32
|
+
`${unexpectedKeys.join(
|
|
33
|
+
",",
|
|
34
|
+
)}: there is no such configuration on "${urlType}"`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
resolvers[urlType] = createNodeEsmResolver({
|
|
38
|
+
build: kitchenContext.build,
|
|
39
|
+
runtimeCompat,
|
|
40
|
+
packageConditions,
|
|
41
|
+
preservesSymlink,
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
throw new TypeError(
|
|
45
|
+
`config must be true, false or an object, got ${config} on "${urlType}"`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
43
50
|
if (resolvers.js_module === undefined) {
|
|
44
51
|
resolvers.js_module = nodeEsmResolverDefault;
|
|
45
52
|
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { readFileSync } from "node:fs";
|
|
17
17
|
|
|
18
18
|
export const createNodeEsmResolver = ({
|
|
19
|
+
build,
|
|
19
20
|
runtimeCompat,
|
|
20
21
|
packageConditions,
|
|
21
22
|
preservesSymlink,
|
|
@@ -23,7 +24,7 @@ export const createNodeEsmResolver = ({
|
|
|
23
24
|
const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node");
|
|
24
25
|
// https://nodejs.org/api/esm.html#resolver-algorithm-specification
|
|
25
26
|
packageConditions = packageConditions || [
|
|
26
|
-
...readCustomConditionsFromProcessArgs(),
|
|
27
|
+
...(build ? [] : readCustomConditionsFromProcessArgs()),
|
|
27
28
|
nodeRuntimeEnabled ? "node" : "browser",
|
|
28
29
|
"import",
|
|
29
30
|
];
|
|
@@ -34,11 +35,7 @@ export const createNodeEsmResolver = ({
|
|
|
34
35
|
}
|
|
35
36
|
const { ownerUrlInfo } = reference;
|
|
36
37
|
if (reference.specifierPathname[0] === "/") {
|
|
37
|
-
|
|
38
|
-
reference.specifier.slice(1),
|
|
39
|
-
ownerUrlInfo.context.rootDirectoryUrl,
|
|
40
|
-
);
|
|
41
|
-
return url;
|
|
38
|
+
return null; // let it to jsenv_web_resolution
|
|
42
39
|
}
|
|
43
40
|
let parentUrl;
|
|
44
41
|
if (reference.baseUrl) {
|
|
@@ -49,8 +46,7 @@ export const createNodeEsmResolver = ({
|
|
|
49
46
|
parentUrl = ownerUrlInfo.url;
|
|
50
47
|
}
|
|
51
48
|
if (!parentUrl.startsWith("file:")) {
|
|
52
|
-
|
|
53
|
-
return url;
|
|
49
|
+
return null; // let it to jsenv_web_resolution
|
|
54
50
|
}
|
|
55
51
|
const { url, type, packageDirectoryUrl } = applyNodeEsmResolution({
|
|
56
52
|
conditions: packageConditions,
|
|
@@ -5,18 +5,20 @@ export const jsenvPluginWebResolution = () => {
|
|
|
5
5
|
resolveReference: (reference) => {
|
|
6
6
|
const { ownerUrlInfo } = reference;
|
|
7
7
|
if (reference.specifierPathname[0] === "/") {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
ownerUrlInfo.
|
|
11
|
-
|
|
8
|
+
const resource = reference.specifier;
|
|
9
|
+
if (ownerUrlInfo.originalUrl?.startsWith("http")) {
|
|
10
|
+
return new URL(resource, ownerUrlInfo.originalUrl);
|
|
11
|
+
}
|
|
12
|
+
const url = new URL(resource.slice(1), ownerUrlInfo.entryUrlInfo.url);
|
|
12
13
|
return url;
|
|
13
14
|
}
|
|
14
15
|
// baseUrl happens second argument to new URL() is different from
|
|
15
16
|
// import.meta.url or document.currentScript.src
|
|
16
17
|
const parentUrl =
|
|
17
|
-
reference.baseUrl ||
|
|
18
|
+
reference.baseUrl ||
|
|
19
|
+
(ownerUrlInfo.context.dev
|
|
18
20
|
? ownerUrlInfo.url
|
|
19
|
-
: ownerUrlInfo.originalUrl || ownerUrlInfo.url;
|
|
21
|
+
: ownerUrlInfo.originalUrl || ownerUrlInfo.url);
|
|
20
22
|
const url = new URL(reference.specifier, parentUrl);
|
|
21
23
|
return url;
|
|
22
24
|
},
|
|
@@ -271,7 +271,7 @@ connection_using_websocket: {
|
|
|
271
271
|
websocketUrl,
|
|
272
272
|
{
|
|
273
273
|
logs,
|
|
274
|
-
protocols = [
|
|
274
|
+
protocols = [],
|
|
275
275
|
useEventsToManageConnection = true,
|
|
276
276
|
retry = false,
|
|
277
277
|
retryAfter = 1000,
|
|
@@ -439,7 +439,7 @@ const serverEventsInterface = {
|
|
|
439
439
|
listenEvents: () => {},
|
|
440
440
|
setup: ({ logs }) => {
|
|
441
441
|
const websocketScheme = self.location.protocol === "https:" ? "wss" : "ws";
|
|
442
|
-
const websocketUrl = `${websocketScheme}://${self.location.host}
|
|
442
|
+
const websocketUrl = `${websocketScheme}://${self.location.host}/.internal/events.websocket`;
|
|
443
443
|
const websocketConnection = createWebSocketConnection(websocketUrl, {
|
|
444
444
|
logs,
|
|
445
445
|
retry: true,
|