@jsenv/core 28.4.3 → 28.6.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.
@@ -370,10 +370,4 @@ window.__server_events__.listenEvents({
370
370
  reload: reloadServerEvent => {
371
371
  reloader.addMessage(reloadServerEvent.data);
372
372
  }
373
- }); // const findHotMetaUrl = (originalFileRelativeUrl) => {
374
- // return Object.keys(urlHotMetas).find((compileUrl) => {
375
- // return (
376
- // parseCompiledUrl(compileUrl).fileRelativeUrl === originalFileRelativeUrl
377
- // )
378
- // })
379
- // }
373
+ });
@@ -230,7 +230,15 @@ window.__supervisor__ = (() => {
230
230
  line,
231
231
  column
232
232
  }) => {
233
- return typeof line === "number" && typeof column === "number" ? `${url}:${line}:${column}` : typeof line === "number" ? `${url}:${line}` : url;
233
+ if (typeof line === "number" && typeof column === "number") {
234
+ return `${url}:${line}:${column}`;
235
+ }
236
+
237
+ if (typeof line === "number") {
238
+ return `${url}:${line}`;
239
+ }
240
+
241
+ return url;
234
242
  };
235
243
 
236
244
  const resolveUrlSite = ({
@@ -1046,11 +1054,7 @@ window.__supervisor__ = (() => {
1046
1054
  return false;
1047
1055
  }
1048
1056
 
1049
- if (supervisedScriptCandidate.src !== src) {
1050
- return false;
1051
- }
1052
-
1053
- return true;
1057
+ return supervisedScriptCandidate.src === src;
1054
1058
  });
1055
1059
 
1056
1060
  if (supervisedScript) {
package/dist/main.js CHANGED
@@ -3693,7 +3693,7 @@ const formatters = {
3693
3693
  },
3694
3694
  "css_@import": {
3695
3695
  encode: JSON.stringify,
3696
- code: JSON.stringify
3696
+ decode: JSON.stringify
3697
3697
  },
3698
3698
  // https://github.com/webpack-contrib/css-loader/pull/627/files
3699
3699
  "css_url": {
@@ -4516,7 +4516,8 @@ const jsenvPluginUrlAnalysis = ({
4516
4516
  include,
4517
4517
  supportedProtocols = ["file:", "data:", "virtual:", "http:", "https:"]
4518
4518
  }) => {
4519
- let getIncludeInfo = () => undefined;
4519
+ // eslint-disable-next-line no-unused-vars
4520
+ let getIncludeInfo = url => undefined;
4520
4521
 
4521
4522
  if (include) {
4522
4523
  const associations = URL_META.resolveAssociations({
@@ -4570,7 +4571,6 @@ const jsenvPluginUrlAnalysis = ({
4570
4571
 
4571
4572
  if (protocolIsSupported) {
4572
4573
  reference.shouldHandle = true;
4573
- return;
4574
4574
  }
4575
4575
  },
4576
4576
  transformUrlContent: {
@@ -10301,15 +10301,24 @@ const jsenvPluginAsJsClassicHtml = ({
10301
10301
  }
10302
10302
 
10303
10303
  if (needsSystemJs) {
10304
- mutations.push(() => {
10305
- const [systemJsReference] = context.referenceUtils.inject({
10304
+ mutations.push(async () => {
10305
+ const systemJsFileContent = readFileSync$1(new URL(systemJsClientFileUrl), {
10306
+ encoding: "utf8"
10307
+ });
10308
+ const [systemJsReference, systemJsUrlInfo] = context.referenceUtils.inject({
10306
10309
  type: "script_src",
10307
10310
  expectedType: "js_classic",
10308
- specifier: systemJsClientFileUrl
10311
+ isInline: true,
10312
+ contentType: "text/javascript",
10313
+ content: systemJsFileContent,
10314
+ specifier: "s.js"
10315
+ });
10316
+ await context.cook(systemJsUrlInfo, {
10317
+ reference: systemJsReference
10309
10318
  });
10310
10319
  injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
10311
10320
  tagName: "script",
10312
- src: systemJsReference.generatedSpecifier
10321
+ textContent: systemJsUrlInfo.content
10313
10322
  }), "jsenv:as_js_classic_html");
10314
10323
  });
10315
10324
  }
@@ -10319,7 +10328,7 @@ const jsenvPluginAsJsClassicHtml = ({
10319
10328
  return null;
10320
10329
  }
10321
10330
 
10322
- mutations.forEach(mutation => mutation());
10331
+ await Promise.all(mutations.map(mutation => mutation()));
10323
10332
  return stringifyHtmlAst(htmlAst);
10324
10333
  }
10325
10334
  }
@@ -12013,7 +12022,9 @@ const jsenvPluginImportmap = () => {
12013
12022
  };
12014
12023
  };
12015
12024
 
12016
- const jsenvPluginUrlResolution = () => {
12025
+ const jsenvPluginUrlResolution = ({
12026
+ clientMainFileUrl
12027
+ }) => {
12017
12028
  const urlResolver = reference => {
12018
12029
  return new URL(reference.specifier, reference.baseUrl || reference.parentUrl).href;
12019
12030
  };
@@ -12022,8 +12033,13 @@ const jsenvPluginUrlResolution = () => {
12022
12033
  name: "jsenv:url_resolution",
12023
12034
  appliesDuring: "*",
12024
12035
  resolveUrl: {
12025
- "http_request": urlResolver,
12026
- // during dev
12036
+ "http_request": reference => {
12037
+ if (reference.specifier === "/") {
12038
+ return String(clientMainFileUrl);
12039
+ }
12040
+
12041
+ return urlResolver(reference);
12042
+ },
12027
12043
  "entry_point": urlResolver,
12028
12044
  // during build
12029
12045
  "link_href": urlResolver,
@@ -13140,7 +13156,17 @@ const mainLegacyResolvers = {
13140
13156
  return null;
13141
13157
  },
13142
13158
  browser: (packageJson, packageUrl) => {
13143
- const browserMain = typeof packageJson.browser === "string" ? packageJson.browser : typeof packageJson.browser === "object" && packageJson.browser !== null ? packageJson.browser["."] : "";
13159
+ const browserMain = (() => {
13160
+ if (typeof packageJson.browser === "string") {
13161
+ return packageJson.browser;
13162
+ }
13163
+
13164
+ if (typeof packageJson.browser === "object" && packageJson.browser !== null) {
13165
+ return packageJson.browser["."];
13166
+ }
13167
+
13168
+ return "";
13169
+ })();
13144
13170
 
13145
13171
  if (!browserMain) {
13146
13172
  if (typeof packageJson.module === "string") {
@@ -16552,16 +16578,10 @@ const htmlNodeCanHotReload = node => {
16552
16578
  }
16553
16579
 
16554
16580
  if (isResourceHint) {
16555
- // for resource hints html will be notified the underlying resource has changed
16556
- // but we won't do anything (if the resource is deleted we should?)
16557
- return true;
16558
- }
16559
-
16560
- if (rel === "icon") {
16561
- return true;
16581
+ return false;
16562
16582
  }
16563
16583
 
16564
- return false;
16584
+ return rel === "icon";
16565
16585
  }
16566
16586
 
16567
16587
  return [// "script_src", // script src cannot hot reload
@@ -16985,8 +17005,6 @@ const jsenvPluginAutoreloadServer = ({
16985
17005
  return dependentPropagationResult;
16986
17006
  } // declined by absence of boundary, we can keep searching
16987
17007
 
16988
-
16989
- continue;
16990
17008
  }
16991
17009
 
16992
17010
  if (instructions.length === 0) {
@@ -17152,62 +17170,64 @@ const jsenvPluginCacheControl = () => {
17152
17170
  };
17153
17171
  const SECONDS_IN_30_DAYS$1 = 60 * 60 * 24 * 30;
17154
17172
 
17173
+ const explorerHtmlFileUrl = new URL("./html/explorer.html", import.meta.url);
17155
17174
  const jsenvPluginExplorer = ({
17156
- groups
17175
+ groups = {
17176
+ src: {
17177
+ "./src/**/*.html": true
17178
+ },
17179
+ tests: {
17180
+ "./tests/**/*.test.html": true
17181
+ }
17182
+ }
17157
17183
  }) => {
17158
- const htmlClientFileUrl = new URL("./html/explorer.html", import.meta.url);
17159
17184
  const faviconClientFileUrl = new URL("./other/jsenv.png", import.meta.url);
17160
17185
  return {
17161
17186
  name: "jsenv:explorer",
17162
17187
  appliesDuring: "dev",
17163
- serve: async (request, {
17164
- rootDirectoryUrl
17165
- }) => {
17166
- if (request.pathname !== "/") {
17167
- return null;
17168
- }
17188
+ transformUrlContent: {
17189
+ html: async (urlInfo, context) => {
17190
+ if (urlInfo.url !== explorerHtmlFileUrl) {
17191
+ return null;
17192
+ }
17169
17193
 
17170
- const associationsForExplorable = {};
17171
- Object.keys(groups).forEach(groupName => {
17172
- const groupConfig = groups[groupName];
17173
- associationsForExplorable[groupName] = {
17174
- "**/.jsenv/": false,
17175
- // avoid visting .jsenv directory in jsenv itself
17176
- ...groupConfig
17177
- };
17178
- });
17179
- const matchingFileResultArray = await collectFiles({
17180
- directoryUrl: rootDirectoryUrl,
17181
- associations: associationsForExplorable,
17182
- predicate: meta => Object.keys(meta).some(group => Boolean(meta[group]))
17183
- });
17184
- const files = matchingFileResultArray.map(({
17185
- relativeUrl,
17186
- meta
17187
- }) => ({
17188
- relativeUrl,
17189
- meta
17190
- }));
17191
- let html = String(readFileSync$1(new URL(htmlClientFileUrl)));
17192
- html = html.replace("ignore:FAVICON_HREF", DATA_URL.stringify({
17193
- contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
17194
- base64Flag: true,
17195
- data: readFileSync$1(new URL(faviconClientFileUrl)).toString("base64")
17196
- }));
17197
- html = html.replace("SERVER_PARAMS", JSON.stringify({
17198
- rootDirectoryUrl,
17199
- groups,
17200
- files
17201
- }, null, " "));
17202
- return {
17203
- status: 200,
17204
- headers: {
17205
- "cache-control": "no-store",
17206
- "content-type": "text/html",
17207
- "content-length": Buffer.byteLength(html)
17208
- },
17209
- body: html
17210
- };
17194
+ const associationsForExplorable = {};
17195
+ Object.keys(groups).forEach(groupName => {
17196
+ const groupConfig = groups[groupName];
17197
+ associationsForExplorable[groupName] = {
17198
+ "**/.jsenv/": false,
17199
+ // avoid visting .jsenv directory in jsenv itself
17200
+ ...groupConfig
17201
+ };
17202
+ });
17203
+ const matchingFileResultArray = await collectFiles({
17204
+ directoryUrl: context.rootDirectoryUrl,
17205
+ associations: associationsForExplorable,
17206
+ predicate: meta => Object.keys(meta).some(group => Boolean(meta[group]))
17207
+ });
17208
+ const files = matchingFileResultArray.map(({
17209
+ relativeUrl,
17210
+ meta
17211
+ }) => ({
17212
+ relativeUrl,
17213
+ meta
17214
+ }));
17215
+ let html = urlInfo.content;
17216
+ html = html.replace("ignore:FAVICON_HREF", DATA_URL.stringify({
17217
+ contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
17218
+ base64Flag: true,
17219
+ data: readFileSync$1(new URL(faviconClientFileUrl)).toString("base64")
17220
+ }));
17221
+ html = html.replace("SERVER_PARAMS", JSON.stringify({
17222
+ rootDirectoryUrl: context.rootDirectoryUrl,
17223
+ groups,
17224
+ files
17225
+ }, null, " "));
17226
+ Object.assign(urlInfo.headers, {
17227
+ "cache-control": "no-store"
17228
+ });
17229
+ return html;
17230
+ }
17211
17231
  }
17212
17232
  };
17213
17233
  };
@@ -17223,11 +17243,16 @@ const getCorePlugins = ({
17223
17243
  transpilation = true,
17224
17244
  minification = false,
17225
17245
  bundling = false,
17246
+ clientMainFileUrl,
17226
17247
  clientAutoreload = false,
17227
17248
  clientFileChangeCallbackList,
17228
17249
  clientFilesPruneCallbackList,
17229
17250
  explorer
17230
17251
  } = {}) => {
17252
+ if (explorer === true) {
17253
+ explorer = {};
17254
+ }
17255
+
17231
17256
  if (supervisor === true) {
17232
17257
  supervisor = {};
17233
17258
  }
@@ -17244,6 +17269,7 @@ const getCorePlugins = ({
17244
17269
  clientAutoreload = {};
17245
17270
  }
17246
17271
 
17272
+ clientMainFileUrl = clientMainFileUrl || explorer ? explorerHtmlFileUrl : new URL("./index.html", rootDirectoryUrl);
17247
17273
  return [jsenvPluginUrlAnalysis({
17248
17274
  rootDirectoryUrl,
17249
17275
  ...urlAnalysis
@@ -17255,7 +17281,9 @@ const getCorePlugins = ({
17255
17281
  directoryReferenceAllowed,
17256
17282
  ...fileSystemMagicResolution
17257
17283
  }), jsenvPluginHttpUrls(), jsenvPluginLeadingSlash(), // before url resolution to handle "js_import_export" resolution
17258
- jsenvPluginNodeEsmResolution(nodeEsmResolution), jsenvPluginUrlResolution(), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
17284
+ jsenvPluginNodeEsmResolution(nodeEsmResolution), jsenvPluginUrlResolution({
17285
+ clientMainFileUrl
17286
+ }), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
17259
17287
  runtimeCompat
17260
17288
  }), jsenvPluginBundling(bundling), jsenvPluginMinification(minification), jsenvPluginImportMetaHot(), ...(clientAutoreload ? [jsenvPluginAutoreload({ ...clientAutoreload,
17261
17289
  clientFileChangeCallbackList,
@@ -20216,13 +20244,8 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
20216
20244
  // - happens for "as_js_classic" injecting "s.js"
20217
20245
 
20218
20246
  if (reference.injected) {
20219
- const [ref, rawUrlInfo] = rawGraphKitchen.injectReference({
20220
- type: reference.type,
20221
- expectedType: reference.expectedType,
20222
- expectedSubtype: reference.expectedSubtype,
20223
- parentUrl: buildToRawUrls[reference.parentUrl],
20224
- specifier: reference.specifier,
20225
- injected: true
20247
+ const [ref, rawUrlInfo] = rawGraphKitchen.injectReference({ ...reference,
20248
+ parentUrl: buildToRawUrls[reference.parentUrl]
20226
20249
  });
20227
20250
  await rawGraphKitchen.cook(rawUrlInfo, {
20228
20251
  reference: ref
@@ -23275,7 +23298,8 @@ const startServer = async ({
23275
23298
  preferIpv6
23276
23299
  });
23277
23300
  serverOrigins.externalip = createOrigin(firstExternalIp);
23278
- } else if (hostnameInfo.label === "loopback") {} else {
23301
+ } else if (hostnameInfo.label === "loopback") {// nothing
23302
+ } else {
23279
23303
  serverOrigins.local = createOrigin(hostname);
23280
23304
  }
23281
23305
  } else {
@@ -24016,6 +24040,10 @@ const startServer = async ({
24016
24040
  const removeUpgradeCallback = listenEvent(facadeServer, "upgrade", upgradeCallback);
24017
24041
  stopCallbackList.add(removeUpgradeCallback);
24018
24042
  stopCallbackList.add(() => {
24043
+ websocketClients.forEach(websocketClient => {
24044
+ websocketClient.close();
24045
+ });
24046
+ websocketClients.clear();
24019
24047
  websocketServer.close();
24020
24048
  websocketServer = null;
24021
24049
  });
@@ -25252,6 +25280,7 @@ const createFileService = ({
25252
25280
  transpilation,
25253
25281
  clientAutoreload,
25254
25282
  clientFiles,
25283
+ clientMainFileUrl,
25255
25284
  cooldownBetweenFileEvents,
25256
25285
  explorer,
25257
25286
  sourcemaps,
@@ -25360,6 +25389,7 @@ const createFileService = ({
25360
25389
  nodeEsmResolution,
25361
25390
  fileSystemMagicResolution,
25362
25391
  transpilation,
25392
+ clientMainFileUrl,
25363
25393
  clientAutoreload,
25364
25394
  clientFileChangeCallbackList,
25365
25395
  clientFilesPruneCallbackList,
@@ -25369,7 +25399,7 @@ const createFileService = ({
25369
25399
  sourcemapsSourcesProtocol,
25370
25400
  sourcemapsSourcesContent,
25371
25401
  writeGeneratedFiles,
25372
- outDirectoryUrl: scenarios.dev ? `${rootDirectoryUrl}.jsenv/${runtimeName}@${runtimeVersion}/` : `${rootDirectoryUrl}.jsenv/${scenarios.test ? "test" : "build"}/${runtimeName}@${runtimeVersion}/`
25402
+ outDirectoryUrl: scenarios.dev ? `${rootDirectoryUrl}.jsenv/${runtimeName}@${runtimeVersion}/` : `${rootDirectoryUrl}.jsenv/build/${runtimeName}@${runtimeVersion}/`
25373
25403
  });
25374
25404
 
25375
25405
  urlGraph.createUrlInfoCallbackRef.current = urlInfo => {
@@ -25592,7 +25622,9 @@ const createFileService = ({
25592
25622
  url: reference.url,
25593
25623
  status: 200,
25594
25624
  // let the browser re-throw the syntax error
25595
- statusText: originalError.reason,
25625
+ // reason becomes the http response statusText, it must not contain invalid chars
25626
+ // https://github.com/nodejs/node/blob/0c27ca4bc9782d658afeaebcec85ec7b28f1cc35/lib/_http_common.js#L221
25627
+ statusText: e.reason,
25596
25628
  statusMessage: originalError.message,
25597
25629
  headers: {
25598
25630
  "content-type": urlInfo.contentType,
@@ -25695,6 +25727,7 @@ const startOmegaServer = async ({
25695
25727
  transpilation,
25696
25728
  clientAutoreload,
25697
25729
  clientFiles,
25730
+ clientMainFileUrl,
25698
25731
  cooldownBetweenFileEvents,
25699
25732
  explorer,
25700
25733
  sourcemaps,
@@ -25748,6 +25781,7 @@ const startOmegaServer = async ({
25748
25781
  transpilation,
25749
25782
  clientAutoreload,
25750
25783
  clientFiles,
25784
+ clientMainFileUrl,
25751
25785
  cooldownBetweenFileEvents,
25752
25786
  explorer,
25753
25787
  sourcemaps,
@@ -25842,6 +25876,7 @@ const startDevServer = async ({
25842
25876
  "./jsenv.config.mjs": true
25843
25877
  },
25844
25878
  clientAutoreload = true,
25879
+ clientMainFileUrl,
25845
25880
  devServerAutoreload = false,
25846
25881
  devServerMainFile = getCallerPosition().url,
25847
25882
  cooldownBetweenFileEvents,
@@ -25855,16 +25890,8 @@ const startDevServer = async ({
25855
25890
  nodeEsmResolution,
25856
25891
  fileSystemMagicResolution,
25857
25892
  transpilation,
25858
- explorer = {
25859
- groups: {
25860
- src: {
25861
- "./src/**/*.html": true
25862
- },
25863
- tests: {
25864
- "./tests/**/*.test.html": true
25865
- }
25866
- }
25867
- },
25893
+ explorer = true,
25894
+ // see jsenv_plugin_explorer.js
25868
25895
  // toolbar = false,
25869
25896
  sourcemaps = "inline",
25870
25897
  sourcemapsSourcesProtocol,
@@ -25944,10 +25971,7 @@ const startDevServer = async ({
25944
25971
  const messagePromise = new Promise(resolve => {
25945
25972
  worker.once("message", resolve);
25946
25973
  });
25947
- const origin = await messagePromise; // if (!keepProcessAlive) {
25948
- // worker.unref()
25949
- // }
25950
-
25974
+ const origin = await messagePromise;
25951
25975
  return {
25952
25976
  origin,
25953
25977
  stop: () => {
@@ -25984,6 +26008,7 @@ const startDevServer = async ({
25984
26008
  fileSystemMagicResolution,
25985
26009
  transpilation,
25986
26010
  clientFiles,
26011
+ clientMainFileUrl,
25987
26012
  clientAutoreload,
25988
26013
  cooldownBetweenFileEvents,
25989
26014
  explorer,
@@ -28289,7 +28314,6 @@ const createRuntimeFromPlaywright = ({
28289
28314
  });
28290
28315
  }
28291
28316
  });
28292
- return;
28293
28317
  };
28294
28318
 
28295
28319
  try {
@@ -28416,11 +28440,7 @@ const isTargetClosedError = error => {
28416
28440
  return true;
28417
28441
  }
28418
28442
 
28419
- if (error.message.includes("browserContext.close: Browser closed")) {
28420
- return true;
28421
- }
28422
-
28423
- return false;
28443
+ return error.message.includes("browserContext.close: Browser closed");
28424
28444
  };
28425
28445
 
28426
28446
  const extractTextFromConsoleMessage = consoleMessage => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "28.4.3",
3
+ "version": "28.6.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -528,12 +528,8 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
528
528
  // - happens for "as_js_classic" injecting "s.js"
529
529
  if (reference.injected) {
530
530
  const [ref, rawUrlInfo] = rawGraphKitchen.injectReference({
531
- type: reference.type,
532
- expectedType: reference.expectedType,
533
- expectedSubtype: reference.expectedSubtype,
531
+ ...reference,
534
532
  parentUrl: buildToRawUrls[reference.parentUrl],
535
- specifier: reference.specifier,
536
- injected: true,
537
533
  })
538
534
  await rawGraphKitchen.cook(rawUrlInfo, { reference: ref })
539
535
  return rawUrlInfo
@@ -39,6 +39,7 @@ export const startDevServer = async ({
39
39
  "./jsenv.config.mjs": true,
40
40
  },
41
41
  clientAutoreload = true,
42
+ clientMainFileUrl,
42
43
  devServerAutoreload = false,
43
44
  devServerMainFile = getCallerPosition().url,
44
45
  cooldownBetweenFileEvents,
@@ -53,16 +54,7 @@ export const startDevServer = async ({
53
54
  nodeEsmResolution,
54
55
  fileSystemMagicResolution,
55
56
  transpilation,
56
- explorer = {
57
- groups: {
58
- src: {
59
- "./src/**/*.html": true,
60
- },
61
- tests: {
62
- "./tests/**/*.test.html": true,
63
- },
64
- },
65
- },
57
+ explorer = true, // see jsenv_plugin_explorer.js
66
58
  // toolbar = false,
67
59
 
68
60
  sourcemaps = "inline",
@@ -128,9 +120,6 @@ export const startDevServer = async ({
128
120
  worker.once("message", resolve)
129
121
  })
130
122
  const origin = await messagePromise
131
- // if (!keepProcessAlive) {
132
- // worker.unref()
133
- // }
134
123
  return {
135
124
  origin,
136
125
  stop: () => {
@@ -168,6 +157,7 @@ export const startDevServer = async ({
168
157
  fileSystemMagicResolution,
169
158
  transpilation,
170
159
  clientFiles,
160
+ clientMainFileUrl,
171
161
  clientAutoreload,
172
162
  cooldownBetweenFileEvents,
173
163
  explorer,
@@ -355,7 +355,6 @@ export const createRuntimeFromPlaywright = ({
355
355
  })
356
356
  }
357
357
  })
358
- return
359
358
  }
360
359
 
361
360
  try {
@@ -479,10 +478,7 @@ const isTargetClosedError = (error) => {
479
478
  if (error.message.match(/Protocol error \(.*?\): Browser.*?closed/)) {
480
479
  return true
481
480
  }
482
- if (error.message.includes("browserContext.close: Browser closed")) {
483
- return true
484
- }
485
- return false
481
+ return error.message.includes("browserContext.close: Browser closed")
486
482
  }
487
483
 
488
484
  const extractTextFromConsoleMessage = (consoleMessage) => {
@@ -36,6 +36,7 @@ export const startOmegaServer = async ({
36
36
  transpilation,
37
37
  clientAutoreload,
38
38
  clientFiles,
39
+ clientMainFileUrl,
39
40
  cooldownBetweenFileEvents,
40
41
  explorer,
41
42
  sourcemaps,
@@ -98,6 +99,7 @@ export const startOmegaServer = async ({
98
99
  transpilation,
99
100
  clientAutoreload,
100
101
  clientFiles,
102
+ clientMainFileUrl,
101
103
  cooldownBetweenFileEvents,
102
104
  explorer,
103
105
  sourcemaps,
@@ -32,6 +32,7 @@ export const createFileService = ({
32
32
  transpilation,
33
33
  clientAutoreload,
34
34
  clientFiles,
35
+ clientMainFileUrl,
35
36
  cooldownBetweenFileEvents,
36
37
  explorer,
37
38
  sourcemaps,
@@ -132,6 +133,7 @@ export const createFileService = ({
132
133
  fileSystemMagicResolution,
133
134
  transpilation,
134
135
 
136
+ clientMainFileUrl,
135
137
  clientAutoreload,
136
138
  clientFileChangeCallbackList,
137
139
  clientFilesPruneCallbackList,
@@ -144,9 +146,7 @@ export const createFileService = ({
144
146
  writeGeneratedFiles,
145
147
  outDirectoryUrl: scenarios.dev
146
148
  ? `${rootDirectoryUrl}.jsenv/${runtimeName}@${runtimeVersion}/`
147
- : `${rootDirectoryUrl}.jsenv/${
148
- scenarios.test ? "test" : "build"
149
- }/${runtimeName}@${runtimeVersion}/`,
149
+ : `${rootDirectoryUrl}.jsenv/build/${runtimeName}@${runtimeVersion}/`,
150
150
  })
151
151
  urlGraph.createUrlInfoCallbackRef.current = (urlInfo) => {
152
152
  const { watch } = URL_META.applyAssociations({
@@ -352,7 +352,9 @@ export const createFileService = ({
352
352
  return {
353
353
  url: reference.url,
354
354
  status: 200, // let the browser re-throw the syntax error
355
- statusText: originalError.reason,
355
+ // reason becomes the http response statusText, it must not contain invalid chars
356
+ // https://github.com/nodejs/node/blob/0c27ca4bc9782d658afeaebcec85ec7b28f1cc35/lib/_http_common.js#L221
357
+ statusText: e.reason,
356
358
  statusMessage: originalError.message,
357
359
  headers: {
358
360
  "content-type": urlInfo.contentType,
@@ -31,7 +31,7 @@ export const urlSpecifierEncoding = {
31
31
  const formatters = {
32
32
  "js_import_export": { encode: JSON.stringify, decode: JSON.parse },
33
33
  "js_url_specifier": { encode: JSON.stringify, decode: JSON.parse },
34
- "css_@import": { encode: JSON.stringify, code: JSON.stringify },
34
+ "css_@import": { encode: JSON.stringify, decode: JSON.stringify },
35
35
  // https://github.com/webpack-contrib/css-loader/pull/627/files
36
36
  "css_url": {
37
37
  encode: (url) => {
@@ -197,11 +197,3 @@ window.__server_events__.listenEvents({
197
197
  reloader.addMessage(reloadServerEvent.data)
198
198
  },
199
199
  })
200
-
201
- // const findHotMetaUrl = (originalFileRelativeUrl) => {
202
- // return Object.keys(urlHotMetas).find((compileUrl) => {
203
- // return (
204
- // parseCompiledUrl(compileUrl).fileRelativeUrl === originalFileRelativeUrl
205
- // )
206
- // })
207
- // }
@@ -99,7 +99,6 @@ export const jsenvPluginAutoreloadServer = ({
99
99
  return dependentPropagationResult
100
100
  }
101
101
  // declined by absence of boundary, we can keep searching
102
- continue
103
102
  }
104
103
  if (instructions.length === 0) {
105
104
  return {
@@ -3,65 +3,77 @@ import { DATA_URL } from "@jsenv/urls"
3
3
  import { collectFiles } from "@jsenv/filesystem"
4
4
  import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js"
5
5
 
6
- export const jsenvPluginExplorer = ({ groups }) => {
7
- const htmlClientFileUrl = new URL("./client/explorer.html", import.meta.url)
6
+ export const explorerHtmlFileUrl = new URL(
7
+ "./client/explorer.html",
8
+ import.meta.url,
9
+ )
10
+
11
+ export const jsenvPluginExplorer = ({
12
+ groups = {
13
+ src: {
14
+ "./src/**/*.html": true,
15
+ },
16
+ tests: {
17
+ "./tests/**/*.test.html": true,
18
+ },
19
+ },
20
+ }) => {
8
21
  const faviconClientFileUrl = new URL("./client/jsenv.png", import.meta.url)
9
22
 
10
23
  return {
11
24
  name: "jsenv:explorer",
12
25
  appliesDuring: "dev",
13
- serve: async (request, { rootDirectoryUrl }) => {
14
- if (request.pathname !== "/") {
15
- return null
16
- }
17
- const associationsForExplorable = {}
18
- Object.keys(groups).forEach((groupName) => {
19
- const groupConfig = groups[groupName]
20
- associationsForExplorable[groupName] = {
21
- "**/.jsenv/": false, // avoid visting .jsenv directory in jsenv itself
22
- ...groupConfig,
26
+ transformUrlContent: {
27
+ html: async (urlInfo, context) => {
28
+ if (urlInfo.url !== explorerHtmlFileUrl) {
29
+ return null
23
30
  }
24
- })
25
- const matchingFileResultArray = await collectFiles({
26
- directoryUrl: rootDirectoryUrl,
27
- associations: associationsForExplorable,
28
- predicate: (meta) =>
29
- Object.keys(meta).some((group) => Boolean(meta[group])),
30
- })
31
- const files = matchingFileResultArray.map(({ relativeUrl, meta }) => ({
32
- relativeUrl,
33
- meta,
34
- }))
35
- let html = String(readFileSync(new URL(htmlClientFileUrl)))
36
- html = html.replace(
37
- "ignore:FAVICON_HREF",
38
- DATA_URL.stringify({
39
- contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
40
- base64Flag: true,
41
- data: readFileSync(new URL(faviconClientFileUrl)).toString("base64"),
42
- }),
43
- )
44
- html = html.replace(
45
- "SERVER_PARAMS",
46
- JSON.stringify(
47
- {
48
- rootDirectoryUrl,
49
- groups,
50
- files,
51
- },
52
- null,
53
- " ",
54
- ),
55
- )
56
- return {
57
- status: 200,
58
- headers: {
31
+ const associationsForExplorable = {}
32
+ Object.keys(groups).forEach((groupName) => {
33
+ const groupConfig = groups[groupName]
34
+ associationsForExplorable[groupName] = {
35
+ "**/.jsenv/": false, // avoid visting .jsenv directory in jsenv itself
36
+ ...groupConfig,
37
+ }
38
+ })
39
+ const matchingFileResultArray = await collectFiles({
40
+ directoryUrl: context.rootDirectoryUrl,
41
+ associations: associationsForExplorable,
42
+ predicate: (meta) =>
43
+ Object.keys(meta).some((group) => Boolean(meta[group])),
44
+ })
45
+ const files = matchingFileResultArray.map(({ relativeUrl, meta }) => ({
46
+ relativeUrl,
47
+ meta,
48
+ }))
49
+ let html = urlInfo.content
50
+ html = html.replace(
51
+ "ignore:FAVICON_HREF",
52
+ DATA_URL.stringify({
53
+ contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
54
+ base64Flag: true,
55
+ data: readFileSync(new URL(faviconClientFileUrl)).toString(
56
+ "base64",
57
+ ),
58
+ }),
59
+ )
60
+ html = html.replace(
61
+ "SERVER_PARAMS",
62
+ JSON.stringify(
63
+ {
64
+ rootDirectoryUrl: context.rootDirectoryUrl,
65
+ groups,
66
+ files,
67
+ },
68
+ null,
69
+ " ",
70
+ ),
71
+ )
72
+ Object.assign(urlInfo.headers, {
59
73
  "cache-control": "no-store",
60
- "content-type": "text/html",
61
- "content-length": Buffer.byteLength(html),
62
- },
63
- body: html,
64
- }
74
+ })
75
+ return html
76
+ },
65
77
  },
66
78
  }
67
79
  }
@@ -125,14 +125,9 @@ const htmlNodeCanHotReload = (node) => {
125
125
  return true
126
126
  }
127
127
  if (isResourceHint) {
128
- // for resource hints html will be notified the underlying resource has changed
129
- // but we won't do anything (if the resource is deleted we should?)
130
- return true
131
- }
132
- if (rel === "icon") {
133
- return true
128
+ return false
134
129
  }
135
- return false
130
+ return rel === "icon"
136
131
  }
137
132
  return [
138
133
  // "script_src", // script src cannot hot reload
@@ -20,7 +20,10 @@ import { jsenvPluginImportMetaHot } from "./import_meta_hot/jsenv_plugin_import_
20
20
  import { jsenvPluginAutoreload } from "./autoreload/jsenv_plugin_autoreload.js"
21
21
  import { jsenvPluginCacheControl } from "./cache_control/jsenv_plugin_cache_control.js"
22
22
  // dev only
23
- import { jsenvPluginExplorer } from "./explorer/jsenv_plugin_explorer.js"
23
+ import {
24
+ explorerHtmlFileUrl,
25
+ jsenvPluginExplorer,
26
+ } from "./explorer/jsenv_plugin_explorer.js"
24
27
 
25
28
  export const getCorePlugins = ({
26
29
  rootDirectoryUrl,
@@ -35,11 +38,15 @@ export const getCorePlugins = ({
35
38
  minification = false,
36
39
  bundling = false,
37
40
 
41
+ clientMainFileUrl,
38
42
  clientAutoreload = false,
39
43
  clientFileChangeCallbackList,
40
44
  clientFilesPruneCallbackList,
41
45
  explorer,
42
46
  } = {}) => {
47
+ if (explorer === true) {
48
+ explorer = {}
49
+ }
43
50
  if (supervisor === true) {
44
51
  supervisor = {}
45
52
  }
@@ -52,6 +59,10 @@ export const getCorePlugins = ({
52
59
  if (clientAutoreload === true) {
53
60
  clientAutoreload = {}
54
61
  }
62
+ clientMainFileUrl =
63
+ clientMainFileUrl || explorer
64
+ ? explorerHtmlFileUrl
65
+ : new URL("./index.html", rootDirectoryUrl)
55
66
 
56
67
  return [
57
68
  jsenvPluginUrlAnalysis({ rootDirectoryUrl, ...urlAnalysis }),
@@ -69,7 +80,7 @@ export const getCorePlugins = ({
69
80
  jsenvPluginLeadingSlash(),
70
81
  // before url resolution to handle "js_import_export" resolution
71
82
  jsenvPluginNodeEsmResolution(nodeEsmResolution),
72
- jsenvPluginUrlResolution(),
83
+ jsenvPluginUrlResolution({ clientMainFileUrl }),
73
84
  jsenvPluginUrlVersion(),
74
85
  jsenvPluginCommonJsGlobals(),
75
86
  jsenvPluginImportMetaScenarios(),
@@ -191,11 +191,13 @@ window.__supervisor__ = (() => {
191
191
  }
192
192
 
193
193
  const stringifyUrlSite = ({ url, line, column }) => {
194
- return typeof line === "number" && typeof column === "number"
195
- ? `${url}:${line}:${column}`
196
- : typeof line === "number"
197
- ? `${url}:${line}`
198
- : url
194
+ if (typeof line === "number" && typeof column === "number") {
195
+ return `${url}:${line}:${column}`
196
+ }
197
+ if (typeof line === "number") {
198
+ return `${url}:${line}`
199
+ }
200
+ return url
199
201
  }
200
202
 
201
203
  const resolveUrlSite = ({ url, line, column }) => {
@@ -913,10 +915,7 @@ window.__supervisor__ = (() => {
913
915
  if (type && supervisedScriptCandidate.type !== type) {
914
916
  return false
915
917
  }
916
- if (supervisedScriptCandidate.src !== src) {
917
- return false
918
- }
919
- return true
918
+ return supervisedScriptCandidate.src === src
920
919
  },
921
920
  )
922
921
  if (supervisedScript) {
@@ -116,9 +116,6 @@ export const fetchUsingXHR = async (
116
116
  if (responseBodyType === "arrayBuffer") {
117
117
  return arrayBufferToText(responseBody)
118
118
  }
119
- // if (responseBodyType === "text" || responseBodyType === 'searchParams') {
120
- // return body
121
- // }
122
119
  return String(responseBody)
123
120
  }
124
121
 
@@ -5,6 +5,7 @@
5
5
  * - <link rel="modulepreload"> are converted to <link rel="preload">
6
6
  */
7
7
 
8
+ import { readFileSync } from "node:fs"
8
9
  import {
9
10
  parseHtmlString,
10
11
  visitHtmlNodes,
@@ -160,17 +161,28 @@ export const jsenvPluginAsJsClassicHtml = ({
160
161
  }
161
162
  }
162
163
  if (needsSystemJs) {
163
- mutations.push(() => {
164
- const [systemJsReference] = context.referenceUtils.inject({
165
- type: "script_src",
166
- expectedType: "js_classic",
167
- specifier: systemJsClientFileUrl,
164
+ mutations.push(async () => {
165
+ const systemJsFileContent = readFileSync(
166
+ new URL(systemJsClientFileUrl),
167
+ { encoding: "utf8" },
168
+ )
169
+ const [systemJsReference, systemJsUrlInfo] =
170
+ context.referenceUtils.inject({
171
+ type: "script_src",
172
+ expectedType: "js_classic",
173
+ isInline: true,
174
+ contentType: "text/javascript",
175
+ content: systemJsFileContent,
176
+ specifier: "s.js",
177
+ })
178
+ await context.cook(systemJsUrlInfo, {
179
+ reference: systemJsReference,
168
180
  })
169
181
  injectScriptNodeAsEarlyAsPossible(
170
182
  htmlAst,
171
183
  createHtmlNode({
172
184
  tagName: "script",
173
- src: systemJsReference.generatedSpecifier,
185
+ textContent: systemJsUrlInfo.content,
174
186
  }),
175
187
  "jsenv:as_js_classic_html",
176
188
  )
@@ -180,7 +192,7 @@ export const jsenvPluginAsJsClassicHtml = ({
180
192
  if (mutations.length === 0) {
181
193
  return null
182
194
  }
183
- mutations.forEach((mutation) => mutation())
195
+ await Promise.all(mutations.map((mutation) => mutation()))
184
196
  return stringifyHtmlAst(htmlAst)
185
197
  },
186
198
  },
@@ -11,7 +11,8 @@ export const jsenvPluginUrlAnalysis = ({
11
11
  include,
12
12
  supportedProtocols = ["file:", "data:", "virtual:", "http:", "https:"],
13
13
  }) => {
14
- let getIncludeInfo = () => undefined
14
+ // eslint-disable-next-line no-unused-vars
15
+ let getIncludeInfo = (url) => undefined
15
16
  if (include) {
16
17
  const associations = URL_META.resolveAssociations(
17
18
  { include },
@@ -56,7 +57,6 @@ export const jsenvPluginUrlAnalysis = ({
56
57
  )
57
58
  if (protocolIsSupported) {
58
59
  reference.shouldHandle = true
59
- return
60
60
  }
61
61
  },
62
62
  transformUrlContent: {
@@ -1,4 +1,4 @@
1
- export const jsenvPluginUrlResolution = () => {
1
+ export const jsenvPluginUrlResolution = ({ clientMainFileUrl }) => {
2
2
  const urlResolver = (reference) => {
3
3
  return new URL(
4
4
  reference.specifier,
@@ -9,7 +9,12 @@ export const jsenvPluginUrlResolution = () => {
9
9
  name: "jsenv:url_resolution",
10
10
  appliesDuring: "*",
11
11
  resolveUrl: {
12
- "http_request": urlResolver, // during dev
12
+ "http_request": (reference) => {
13
+ if (reference.specifier === "/") {
14
+ return String(clientMainFileUrl)
15
+ }
16
+ return urlResolver(reference)
17
+ },
13
18
  "entry_point": urlResolver, // during build
14
19
  "link_href": urlResolver,
15
20
  "script_src": urlResolver,