@jsenv/core 28.5.1 → 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
@@ -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: {
@@ -12022,7 +12022,9 @@ const jsenvPluginImportmap = () => {
12022
12022
  };
12023
12023
  };
12024
12024
 
12025
- const jsenvPluginUrlResolution = () => {
12025
+ const jsenvPluginUrlResolution = ({
12026
+ clientMainFileUrl
12027
+ }) => {
12026
12028
  const urlResolver = reference => {
12027
12029
  return new URL(reference.specifier, reference.baseUrl || reference.parentUrl).href;
12028
12030
  };
@@ -12031,8 +12033,13 @@ const jsenvPluginUrlResolution = () => {
12031
12033
  name: "jsenv:url_resolution",
12032
12034
  appliesDuring: "*",
12033
12035
  resolveUrl: {
12034
- "http_request": urlResolver,
12035
- // during dev
12036
+ "http_request": reference => {
12037
+ if (reference.specifier === "/") {
12038
+ return String(clientMainFileUrl);
12039
+ }
12040
+
12041
+ return urlResolver(reference);
12042
+ },
12036
12043
  "entry_point": urlResolver,
12037
12044
  // during build
12038
12045
  "link_href": urlResolver,
@@ -13149,7 +13156,17 @@ const mainLegacyResolvers = {
13149
13156
  return null;
13150
13157
  },
13151
13158
  browser: (packageJson, packageUrl) => {
13152
- 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
+ })();
13153
13170
 
13154
13171
  if (!browserMain) {
13155
13172
  if (typeof packageJson.module === "string") {
@@ -16561,16 +16578,10 @@ const htmlNodeCanHotReload = node => {
16561
16578
  }
16562
16579
 
16563
16580
  if (isResourceHint) {
16564
- // for resource hints html will be notified the underlying resource has changed
16565
- // but we won't do anything (if the resource is deleted we should?)
16566
- return true;
16567
- }
16568
-
16569
- if (rel === "icon") {
16570
- return true;
16581
+ return false;
16571
16582
  }
16572
16583
 
16573
- return false;
16584
+ return rel === "icon";
16574
16585
  }
16575
16586
 
16576
16587
  return [// "script_src", // script src cannot hot reload
@@ -16994,8 +17005,6 @@ const jsenvPluginAutoreloadServer = ({
16994
17005
  return dependentPropagationResult;
16995
17006
  } // declined by absence of boundary, we can keep searching
16996
17007
 
16997
-
16998
- continue;
16999
17008
  }
17000
17009
 
17001
17010
  if (instructions.length === 0) {
@@ -17161,62 +17170,64 @@ const jsenvPluginCacheControl = () => {
17161
17170
  };
17162
17171
  const SECONDS_IN_30_DAYS$1 = 60 * 60 * 24 * 30;
17163
17172
 
17173
+ const explorerHtmlFileUrl = new URL("./html/explorer.html", import.meta.url);
17164
17174
  const jsenvPluginExplorer = ({
17165
- groups
17175
+ groups = {
17176
+ src: {
17177
+ "./src/**/*.html": true
17178
+ },
17179
+ tests: {
17180
+ "./tests/**/*.test.html": true
17181
+ }
17182
+ }
17166
17183
  }) => {
17167
- const htmlClientFileUrl = new URL("./html/explorer.html", import.meta.url);
17168
17184
  const faviconClientFileUrl = new URL("./other/jsenv.png", import.meta.url);
17169
17185
  return {
17170
17186
  name: "jsenv:explorer",
17171
17187
  appliesDuring: "dev",
17172
- serve: async (request, {
17173
- rootDirectoryUrl
17174
- }) => {
17175
- if (request.pathname !== "/") {
17176
- return null;
17177
- }
17188
+ transformUrlContent: {
17189
+ html: async (urlInfo, context) => {
17190
+ if (urlInfo.url !== explorerHtmlFileUrl) {
17191
+ return null;
17192
+ }
17178
17193
 
17179
- const associationsForExplorable = {};
17180
- Object.keys(groups).forEach(groupName => {
17181
- const groupConfig = groups[groupName];
17182
- associationsForExplorable[groupName] = {
17183
- "**/.jsenv/": false,
17184
- // avoid visting .jsenv directory in jsenv itself
17185
- ...groupConfig
17186
- };
17187
- });
17188
- const matchingFileResultArray = await collectFiles({
17189
- directoryUrl: rootDirectoryUrl,
17190
- associations: associationsForExplorable,
17191
- predicate: meta => Object.keys(meta).some(group => Boolean(meta[group]))
17192
- });
17193
- const files = matchingFileResultArray.map(({
17194
- relativeUrl,
17195
- meta
17196
- }) => ({
17197
- relativeUrl,
17198
- meta
17199
- }));
17200
- let html = String(readFileSync$1(new URL(htmlClientFileUrl)));
17201
- html = html.replace("ignore:FAVICON_HREF", DATA_URL.stringify({
17202
- contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
17203
- base64Flag: true,
17204
- data: readFileSync$1(new URL(faviconClientFileUrl)).toString("base64")
17205
- }));
17206
- html = html.replace("SERVER_PARAMS", JSON.stringify({
17207
- rootDirectoryUrl,
17208
- groups,
17209
- files
17210
- }, null, " "));
17211
- return {
17212
- status: 200,
17213
- headers: {
17214
- "cache-control": "no-store",
17215
- "content-type": "text/html",
17216
- "content-length": Buffer.byteLength(html)
17217
- },
17218
- body: html
17219
- };
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
+ }
17220
17231
  }
17221
17232
  };
17222
17233
  };
@@ -17232,11 +17243,16 @@ const getCorePlugins = ({
17232
17243
  transpilation = true,
17233
17244
  minification = false,
17234
17245
  bundling = false,
17246
+ clientMainFileUrl,
17235
17247
  clientAutoreload = false,
17236
17248
  clientFileChangeCallbackList,
17237
17249
  clientFilesPruneCallbackList,
17238
17250
  explorer
17239
17251
  } = {}) => {
17252
+ if (explorer === true) {
17253
+ explorer = {};
17254
+ }
17255
+
17240
17256
  if (supervisor === true) {
17241
17257
  supervisor = {};
17242
17258
  }
@@ -17253,6 +17269,7 @@ const getCorePlugins = ({
17253
17269
  clientAutoreload = {};
17254
17270
  }
17255
17271
 
17272
+ clientMainFileUrl = clientMainFileUrl || explorer ? explorerHtmlFileUrl : new URL("./index.html", rootDirectoryUrl);
17256
17273
  return [jsenvPluginUrlAnalysis({
17257
17274
  rootDirectoryUrl,
17258
17275
  ...urlAnalysis
@@ -17264,7 +17281,9 @@ const getCorePlugins = ({
17264
17281
  directoryReferenceAllowed,
17265
17282
  ...fileSystemMagicResolution
17266
17283
  }), jsenvPluginHttpUrls(), jsenvPluginLeadingSlash(), // before url resolution to handle "js_import_export" resolution
17267
- jsenvPluginNodeEsmResolution(nodeEsmResolution), jsenvPluginUrlResolution(), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
17284
+ jsenvPluginNodeEsmResolution(nodeEsmResolution), jsenvPluginUrlResolution({
17285
+ clientMainFileUrl
17286
+ }), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
17268
17287
  runtimeCompat
17269
17288
  }), jsenvPluginBundling(bundling), jsenvPluginMinification(minification), jsenvPluginImportMetaHot(), ...(clientAutoreload ? [jsenvPluginAutoreload({ ...clientAutoreload,
17270
17289
  clientFileChangeCallbackList,
@@ -23279,7 +23298,8 @@ const startServer = async ({
23279
23298
  preferIpv6
23280
23299
  });
23281
23300
  serverOrigins.externalip = createOrigin(firstExternalIp);
23282
- } else if (hostnameInfo.label === "loopback") {} else {
23301
+ } else if (hostnameInfo.label === "loopback") {// nothing
23302
+ } else {
23283
23303
  serverOrigins.local = createOrigin(hostname);
23284
23304
  }
23285
23305
  } else {
@@ -24020,6 +24040,10 @@ const startServer = async ({
24020
24040
  const removeUpgradeCallback = listenEvent(facadeServer, "upgrade", upgradeCallback);
24021
24041
  stopCallbackList.add(removeUpgradeCallback);
24022
24042
  stopCallbackList.add(() => {
24043
+ websocketClients.forEach(websocketClient => {
24044
+ websocketClient.close();
24045
+ });
24046
+ websocketClients.clear();
24023
24047
  websocketServer.close();
24024
24048
  websocketServer = null;
24025
24049
  });
@@ -25256,6 +25280,7 @@ const createFileService = ({
25256
25280
  transpilation,
25257
25281
  clientAutoreload,
25258
25282
  clientFiles,
25283
+ clientMainFileUrl,
25259
25284
  cooldownBetweenFileEvents,
25260
25285
  explorer,
25261
25286
  sourcemaps,
@@ -25364,6 +25389,7 @@ const createFileService = ({
25364
25389
  nodeEsmResolution,
25365
25390
  fileSystemMagicResolution,
25366
25391
  transpilation,
25392
+ clientMainFileUrl,
25367
25393
  clientAutoreload,
25368
25394
  clientFileChangeCallbackList,
25369
25395
  clientFilesPruneCallbackList,
@@ -25373,7 +25399,7 @@ const createFileService = ({
25373
25399
  sourcemapsSourcesProtocol,
25374
25400
  sourcemapsSourcesContent,
25375
25401
  writeGeneratedFiles,
25376
- 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}/`
25377
25403
  });
25378
25404
 
25379
25405
  urlGraph.createUrlInfoCallbackRef.current = urlInfo => {
@@ -25596,7 +25622,9 @@ const createFileService = ({
25596
25622
  url: reference.url,
25597
25623
  status: 200,
25598
25624
  // let the browser re-throw the syntax error
25599
- 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,
25600
25628
  statusMessage: originalError.message,
25601
25629
  headers: {
25602
25630
  "content-type": urlInfo.contentType,
@@ -25699,6 +25727,7 @@ const startOmegaServer = async ({
25699
25727
  transpilation,
25700
25728
  clientAutoreload,
25701
25729
  clientFiles,
25730
+ clientMainFileUrl,
25702
25731
  cooldownBetweenFileEvents,
25703
25732
  explorer,
25704
25733
  sourcemaps,
@@ -25752,6 +25781,7 @@ const startOmegaServer = async ({
25752
25781
  transpilation,
25753
25782
  clientAutoreload,
25754
25783
  clientFiles,
25784
+ clientMainFileUrl,
25755
25785
  cooldownBetweenFileEvents,
25756
25786
  explorer,
25757
25787
  sourcemaps,
@@ -25846,6 +25876,7 @@ const startDevServer = async ({
25846
25876
  "./jsenv.config.mjs": true
25847
25877
  },
25848
25878
  clientAutoreload = true,
25879
+ clientMainFileUrl,
25849
25880
  devServerAutoreload = false,
25850
25881
  devServerMainFile = getCallerPosition().url,
25851
25882
  cooldownBetweenFileEvents,
@@ -25859,16 +25890,8 @@ const startDevServer = async ({
25859
25890
  nodeEsmResolution,
25860
25891
  fileSystemMagicResolution,
25861
25892
  transpilation,
25862
- explorer = {
25863
- groups: {
25864
- src: {
25865
- "./src/**/*.html": true
25866
- },
25867
- tests: {
25868
- "./tests/**/*.test.html": true
25869
- }
25870
- }
25871
- },
25893
+ explorer = true,
25894
+ // see jsenv_plugin_explorer.js
25872
25895
  // toolbar = false,
25873
25896
  sourcemaps = "inline",
25874
25897
  sourcemapsSourcesProtocol,
@@ -25948,10 +25971,7 @@ const startDevServer = async ({
25948
25971
  const messagePromise = new Promise(resolve => {
25949
25972
  worker.once("message", resolve);
25950
25973
  });
25951
- const origin = await messagePromise; // if (!keepProcessAlive) {
25952
- // worker.unref()
25953
- // }
25954
-
25974
+ const origin = await messagePromise;
25955
25975
  return {
25956
25976
  origin,
25957
25977
  stop: () => {
@@ -25988,6 +26008,7 @@ const startDevServer = async ({
25988
26008
  fileSystemMagicResolution,
25989
26009
  transpilation,
25990
26010
  clientFiles,
26011
+ clientMainFileUrl,
25991
26012
  clientAutoreload,
25992
26013
  cooldownBetweenFileEvents,
25993
26014
  explorer,
@@ -28293,7 +28314,6 @@ const createRuntimeFromPlaywright = ({
28293
28314
  });
28294
28315
  }
28295
28316
  });
28296
- return;
28297
28317
  };
28298
28318
 
28299
28319
  try {
@@ -28420,11 +28440,7 @@ const isTargetClosedError = error => {
28420
28440
  return true;
28421
28441
  }
28422
28442
 
28423
- if (error.message.includes("browserContext.close: Browser closed")) {
28424
- return true;
28425
- }
28426
-
28427
- return false;
28443
+ return error.message.includes("browserContext.close: Browser closed");
28428
28444
  };
28429
28445
 
28430
28446
  const extractTextFromConsoleMessage = consoleMessage => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "28.5.1",
3
+ "version": "28.6.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -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,
@@ -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
 
@@ -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,