@jsenv/core 39.9.4 → 39.9.5

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.
@@ -52,7 +52,29 @@ const initAutoreload = ({ mainFilePath }) => {
52
52
  currentExecution: null,
53
53
  reload: () => {
54
54
  const someEffectIsFullReload = reloader.changes.value.some(
55
- (reloadMessage) => reloadMessage.type === "full",
55
+ (reloadMessage) => {
56
+ if (reloadMessage.type === "full") {
57
+ return true;
58
+ }
59
+ if (reloadMessage.type === "hot") {
60
+ for (const reloadInstruction of reloadMessage.hotInstructions) {
61
+ if (reloadInstruction.type === "html") {
62
+ const acceptedByUrl = new URL(
63
+ reloadInstruction.acceptedBy,
64
+ `${window.location.origin}/`,
65
+ ).href;
66
+ const isCurrentHtmlFile = compareTwoUrlPaths(
67
+ acceptedByUrl,
68
+ window.location.href,
69
+ );
70
+ if (isCurrentHtmlFile) {
71
+ return true;
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return false;
77
+ },
56
78
  );
57
79
  if (someEffectIsFullReload) {
58
80
  dispatchBeforeFullReload();
@@ -136,30 +158,32 @@ This could be due to syntax errors or importing non-existent modules (see errors
136
158
  // - code was not executed (code splitting with dynamic import)
137
159
  // - import.meta.hot.accept() is not called (happens for HTML and CSS)
138
160
  if (type === "prune") {
139
- if (urlHotMeta) {
140
- dispatchBeforePrune();
141
- delete urlHotMetas[urlToFetch];
142
- if (urlHotMeta.disposeCallback) {
143
- console.log(
144
- `[jsenv] cleanup ${boundary} (no longer referenced by ${acceptedBy})`,
145
- );
146
- await urlHotMeta.disposeCallback();
147
- }
161
+ if (!urlHotMeta) {
162
+ // code not executed for this url, no need to prune
163
+ continue;
164
+ }
165
+ dispatchBeforePrune();
166
+ delete urlHotMetas[urlToFetch];
167
+ if (urlHotMeta.disposeCallback) {
168
+ console.log(
169
+ `[jsenv] cleanup ${boundary} (no longer referenced by ${acceptedBy})`,
170
+ );
171
+ await urlHotMeta.disposeCallback();
148
172
  }
149
173
  continue;
150
174
  }
151
- if (acceptedBy === boundary) {
152
- console.log(`[jsenv] hot reloading ${boundary} (${cause})`);
153
- } else {
154
- console.log(
155
- `[jsenv] hot reloading ${acceptedBy} usage in ${boundary} (${cause})`,
156
- );
157
- }
158
175
  if (type === "js_module") {
159
176
  if (!urlHotMeta) {
160
- // code was not executed, no need to re-execute it
177
+ // code not yet executed for this url, no need to re-execute it
161
178
  continue;
162
179
  }
180
+ if (acceptedBy === boundary) {
181
+ console.log(`[jsenv] hot reload ${boundary} (${cause})`);
182
+ } else {
183
+ console.log(
184
+ `[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
185
+ );
186
+ }
163
187
  if (urlHotMeta.disposeCallback) {
164
188
  await urlHotMeta.disposeCallback();
165
189
  }
@@ -189,6 +213,13 @@ This could be due to syntax errors or importing non-existent modules (see errors
189
213
  // we are not in that HTML page
190
214
  continue;
191
215
  }
216
+ if (acceptedBy === boundary) {
217
+ console.log(`[jsenv] hot reload ${boundary} (${cause})`);
218
+ } else {
219
+ console.log(
220
+ `[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
221
+ );
222
+ }
192
223
  const urlToReload = new URL(acceptedBy, `${window.location.origin}/`)
193
224
  .href;
194
225
  const domNodesUsingUrl = getDOMNodesUsingUrl(urlToReload);
@@ -218,7 +218,7 @@
218
218
  null,
219
219
  false,
220
220
  );
221
- for (var next = void 0; (next = iter.nextNode()); ) {
221
+ for (var next = undefined; (next = iter.nextNode()); ) {
222
222
  callback(getShadowRoot(next));
223
223
  }
224
224
  }
@@ -225,7 +225,7 @@ var runtime = (function (exports) {
225
225
  // AsyncIterator objects; they just return a Promise for the value of
226
226
  // the final result produced by the iterator.
227
227
  exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) {
228
- if (PromiseImpl === void 0) PromiseImpl = Promise;
228
+ if (PromiseImpl === undefined) PromiseImpl = Promise;
229
229
 
230
230
  var iter = new AsyncIterator(
231
231
  wrap(innerFn, outerFn, self, tryLocsList),
package/dist/js/ws.js CHANGED
@@ -1738,8 +1738,8 @@ function requireBuffer () {
1738
1738
  byteOffset = 0;
1739
1739
  } else if (byteOffset > 0x7fffffff) {
1740
1740
  byteOffset = 0x7fffffff;
1741
- } else if (byteOffset < -0x80000000) {
1742
- byteOffset = -0x80000000;
1741
+ } else if (byteOffset < -2147483648) {
1742
+ byteOffset = -2147483648;
1743
1743
  }
1744
1744
  byteOffset = +byteOffset; // Coerce to Number.
1745
1745
  if (numberIsNaN(byteOffset)) {
@@ -2480,7 +2480,7 @@ function requireBuffer () {
2480
2480
  Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
2481
2481
  value = +value;
2482
2482
  offset = offset >>> 0;
2483
- if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80);
2483
+ if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -128);
2484
2484
  if (value < 0) value = 0xff + value + 1;
2485
2485
  this[offset] = (value & 0xff);
2486
2486
  return offset + 1
@@ -2489,7 +2489,7 @@ function requireBuffer () {
2489
2489
  Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
2490
2490
  value = +value;
2491
2491
  offset = offset >>> 0;
2492
- if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
2492
+ if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -32768);
2493
2493
  this[offset] = (value & 0xff);
2494
2494
  this[offset + 1] = (value >>> 8);
2495
2495
  return offset + 2
@@ -2498,7 +2498,7 @@ function requireBuffer () {
2498
2498
  Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
2499
2499
  value = +value;
2500
2500
  offset = offset >>> 0;
2501
- if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
2501
+ if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -32768);
2502
2502
  this[offset] = (value >>> 8);
2503
2503
  this[offset + 1] = (value & 0xff);
2504
2504
  return offset + 2
@@ -2507,7 +2507,7 @@ function requireBuffer () {
2507
2507
  Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
2508
2508
  value = +value;
2509
2509
  offset = offset >>> 0;
2510
- if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
2510
+ if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -2147483648);
2511
2511
  this[offset] = (value & 0xff);
2512
2512
  this[offset + 1] = (value >>> 8);
2513
2513
  this[offset + 2] = (value >>> 16);
@@ -2518,7 +2518,7 @@ function requireBuffer () {
2518
2518
  Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
2519
2519
  value = +value;
2520
2520
  offset = offset >>> 0;
2521
- if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
2521
+ if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -2147483648);
2522
2522
  if (value < 0) value = 0xffffffff + value + 1;
2523
2523
  this[offset] = (value >>> 24);
2524
2524
  this[offset + 1] = (value >>> 16);
@@ -1968,7 +1968,7 @@ const comparePathnames = (leftPathame, rightPathname) => {
1968
1968
 
1969
1969
  // longer comes first
1970
1970
  if (!leftPartExists) {
1971
- return +1;
1971
+ return 1;
1972
1972
  }
1973
1973
  if (!rightPartExists) {
1974
1974
  return -1;
@@ -1978,7 +1978,7 @@ const comparePathnames = (leftPathame, rightPathname) => {
1978
1978
  const rightPartIsLast = i === rightPartArray.length - 1;
1979
1979
  // folder comes first
1980
1980
  if (leftPartIsLast && !rightPartIsLast) {
1981
- return +1;
1981
+ return 1;
1982
1982
  }
1983
1983
  if (!leftPartIsLast && rightPartIsLast) {
1984
1984
  return -1;
@@ -1995,7 +1995,7 @@ const comparePathnames = (leftPathame, rightPathname) => {
1995
1995
  }
1996
1996
 
1997
1997
  if (leftLength < rightLength) {
1998
- return +1;
1998
+ return 1;
1999
1999
  }
2000
2000
  if (leftLength > rightLength) {
2001
2001
  return -1;
@@ -3900,6 +3900,7 @@ const writeDirectorySync = (
3900
3900
  .slice(0, -1),
3901
3901
  ),
3902
3902
  );
3903
+ destinationStats = null;
3903
3904
  } else {
3904
3905
  throw new Error(
3905
3906
  `cannot write directory at ${destinationPath} because there is a file at ${urlToFileSystemPath(
@@ -3919,10 +3920,14 @@ const writeDirectorySync = (
3919
3920
  }
3920
3921
  throw new Error(`directory already exists at ${destinationPath}`);
3921
3922
  }
3922
- const destinationType = statsToType(destinationStats);
3923
- throw new Error(
3924
- `cannot write directory at ${destinationPath} because there is a ${destinationType}`,
3925
- );
3923
+ if (force) {
3924
+ unlinkSync(destinationPath);
3925
+ } else {
3926
+ const destinationType = statsToType(destinationStats);
3927
+ throw new Error(
3928
+ `cannot write directory at ${destinationPath} because there is a ${destinationType}`,
3929
+ );
3930
+ }
3926
3931
  }
3927
3932
 
3928
3933
  try {
@@ -13056,7 +13061,7 @@ const createReference = ({
13056
13061
  isInline = false,
13057
13062
  content,
13058
13063
  contentType,
13059
- leadsToADirectory = false,
13064
+ fsStat = null,
13060
13065
  debug = false,
13061
13066
  original = null,
13062
13067
  prev = null,
@@ -13117,7 +13122,7 @@ const createReference = ({
13117
13122
  version,
13118
13123
  injected,
13119
13124
  timing: {},
13120
- leadsToADirectory,
13125
+ fsStat,
13121
13126
  debug,
13122
13127
  // for inline resources the reference contains the content
13123
13128
  isInline,
@@ -14038,7 +14043,7 @@ const createUrlInfo = (url, context) => {
14038
14043
  version: reference.version,
14039
14044
  content: reference.content,
14040
14045
  contentType: reference.contentType,
14041
- leadsToADirectory: reference.leadsToADirectory,
14046
+ fsStat: reference.fsStat,
14042
14047
  debug: reference.debug,
14043
14048
  importAttributes: reference.importAttributes,
14044
14049
  astInfo: reference.astInfo,
@@ -14501,7 +14506,7 @@ const createUrlInfoTransformer = ({
14501
14506
  if (
14502
14507
  urlInfo.type === "directory" ||
14503
14508
  // happens when type is "html" to list directory content for example
14504
- urlInfo.firstReference?.leadsToADirectory
14509
+ urlInfo.firstReference?.fsStat?.isDirectory()
14505
14510
  ) {
14506
14511
  // no need to write the directory
14507
14512
  return;
@@ -15585,7 +15590,6 @@ const jsenvPluginDirectoryReferenceEffect = (
15585
15590
  if (pathname[pathname.length - 1] !== "/") {
15586
15591
  return null;
15587
15592
  }
15588
- reference.leadsToADirectory = true;
15589
15593
  reference.expectedType = "directory";
15590
15594
  if (reference.ownerUrlInfo.type === "directory") {
15591
15595
  reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
@@ -16905,11 +16909,7 @@ const jsenvPluginHtmlReferenceAnalysis = ({
16905
16909
  } else {
16906
16910
  position = getHtmlNodeAttributePosition(node, attributeName);
16907
16911
  }
16908
- const {
16909
- line,
16910
- column,
16911
- // originalLine, originalColumn
16912
- } = position;
16912
+ const { line, column, originalLine, originalColumn } = position;
16913
16913
  const debug =
16914
16914
  getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
16915
16915
 
@@ -16942,8 +16942,9 @@ const jsenvPluginHtmlReferenceAnalysis = ({
16942
16942
  subtype,
16943
16943
  expectedType,
16944
16944
  specifier: attributeValue,
16945
- specifierLine: line,
16946
- specifierColumn: column,
16945
+ specifierLine: originalLine === undefined ? line : originalLine,
16946
+ specifierColumn:
16947
+ originalColumn === undefined ? column : originalColumn,
16947
16948
  specifierStart: attributeValueStart,
16948
16949
  specifierEnd: attributeValueEnd,
16949
16950
  isResourceHint,
@@ -18885,11 +18886,6 @@ const createNodeEsmResolver = ({
18885
18886
  return reference.specifier;
18886
18887
  }
18887
18888
  const { ownerUrlInfo } = reference;
18888
- if (reference.specifier === "/") {
18889
- const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
18890
- const url = new URL(mainFilePath, rootDirectoryUrl);
18891
- return url;
18892
- }
18893
18889
  if (reference.specifier[0] === "/") {
18894
18890
  const url = new URL(
18895
18891
  reference.specifier.slice(1),
@@ -19092,11 +19088,6 @@ const jsenvPluginWebResolution = () => {
19092
19088
  appliesDuring: "*",
19093
19089
  resolveReference: (reference) => {
19094
19090
  const { ownerUrlInfo } = reference;
19095
- if (reference.specifier === "/") {
19096
- const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
19097
- const url = new URL(mainFilePath, rootDirectoryUrl);
19098
- return url;
19099
- }
19100
19091
  if (reference.specifier[0] === "/") {
19101
19092
  const url = new URL(
19102
19093
  reference.specifier.slice(1),
@@ -19107,7 +19098,9 @@ const jsenvPluginWebResolution = () => {
19107
19098
  // baseUrl happens second argument to new URL() is different from
19108
19099
  // import.meta.url or document.currentScript.src
19109
19100
  const parentUrl =
19110
- reference.baseUrl || ownerUrlInfo.originalUrl || ownerUrlInfo.url;
19101
+ reference.baseUrl || ownerUrlInfo.context.dev
19102
+ ? ownerUrlInfo.url
19103
+ : ownerUrlInfo.originalUrl || ownerUrlInfo.url;
19111
19104
  const url = new URL(reference.specifier, parentUrl);
19112
19105
  return url;
19113
19106
  },
@@ -19165,7 +19158,6 @@ const jsenvPluginFsRedirection = ({
19165
19158
  return null;
19166
19159
  }
19167
19160
  if (reference.url === "file:///" || reference.url === "file://") {
19168
- reference.leadsToADirectory = true;
19169
19161
  return `ignore:file:///`;
19170
19162
  }
19171
19163
  // ignore all new URL second arg
@@ -19180,27 +19172,19 @@ const jsenvPluginFsRedirection = ({
19180
19172
  // return `ignore:${reference.url}`;
19181
19173
  // }
19182
19174
  const urlObject = new URL(reference.url);
19183
- let stat;
19184
- try {
19185
- stat = readEntryStatSync(urlObject);
19186
- } catch (e) {
19187
- if (e.code === "ENOENT") {
19188
- stat = null;
19189
- } else {
19190
- throw e;
19191
- }
19192
- }
19175
+ let fsStat = readEntryStatSync(urlObject, { nullIfNotFound: true });
19176
+ reference.fsStat = fsStat;
19193
19177
  const { search, hash } = urlObject;
19194
19178
  urlObject.search = "";
19195
19179
  urlObject.hash = "";
19196
- applyStatEffectsOnUrlObject(urlObject, stat);
19180
+ applyFsStatEffectsOnUrlObject(urlObject, fsStat);
19197
19181
  const shouldApplyFilesystemMagicResolution =
19198
19182
  reference.type === "js_import";
19199
19183
  if (shouldApplyFilesystemMagicResolution) {
19200
19184
  const filesystemResolution = applyFileSystemMagicResolution(
19201
19185
  urlObject.href,
19202
19186
  {
19203
- fileStat: stat,
19187
+ fileStat: fsStat,
19204
19188
  magicDirectoryIndex,
19205
19189
  magicExtensions: getExtensionsToTry(
19206
19190
  magicExtensions,
@@ -19209,12 +19193,28 @@ const jsenvPluginFsRedirection = ({
19209
19193
  },
19210
19194
  );
19211
19195
  if (filesystemResolution.stat) {
19212
- stat = filesystemResolution.stat;
19196
+ fsStat = filesystemResolution.stat;
19197
+ reference.fsStat = fsStat;
19213
19198
  urlObject.href = filesystemResolution.url;
19214
- applyStatEffectsOnUrlObject(urlObject, stat);
19199
+ applyFsStatEffectsOnUrlObject(urlObject, fsStat);
19215
19200
  }
19216
19201
  }
19217
- if (!stat) {
19202
+ if (!fsStat) {
19203
+ // for SPA we want to serve the root HTML file only when:
19204
+ // 1. There is no corresponding file on the filesystem
19205
+ // 2. The url pathname does not have an extension
19206
+ // This point assume client is requesting a file when there is an extension
19207
+ // and it assumes all routes will not use extension
19208
+ // 3. The url pathname does not ends with "/"
19209
+ // In that case we assume client explicitely asks to load a directory
19210
+ if (
19211
+ !urlToExtension$1(urlObject) &&
19212
+ !urlToPathname$1(urlObject).endsWith("/")
19213
+ ) {
19214
+ const { mainFilePath, rootDirectoryUrl } =
19215
+ reference.ownerUrlInfo.context;
19216
+ return new URL(mainFilePath, rootDirectoryUrl);
19217
+ }
19218
19218
  return null;
19219
19219
  }
19220
19220
  const urlBeforeSymlinkResolution = urlObject.href;
@@ -19234,15 +19234,19 @@ const jsenvPluginFsRedirection = ({
19234
19234
  };
19235
19235
  };
19236
19236
 
19237
- const applyStatEffectsOnUrlObject = (urlObject, stat) => {
19237
+ const applyFsStatEffectsOnUrlObject = (urlObject, fsStat) => {
19238
+ if (!fsStat) {
19239
+ return;
19240
+ }
19238
19241
  const { pathname } = urlObject;
19239
19242
  const pathnameUsesTrailingSlash = pathname.endsWith("/");
19240
19243
  // force trailing slash on directories
19241
- if (stat && stat.isDirectory() && !pathnameUsesTrailingSlash) {
19242
- urlObject.pathname = `${pathname}/`;
19243
- }
19244
- // otherwise remove trailing slash if any
19245
- if (stat && !stat.isDirectory() && pathnameUsesTrailingSlash) {
19244
+ if (fsStat.isDirectory()) {
19245
+ if (!pathnameUsesTrailingSlash) {
19246
+ urlObject.pathname = `${pathname}/`;
19247
+ }
19248
+ } else if (pathnameUsesTrailingSlash) {
19249
+ // otherwise remove trailing slash if any
19246
19250
  // a warning here? (because it's strange to reference a file with a trailing slash)
19247
19251
  urlObject.pathname = pathname.slice(0, -1);
19248
19252
  }
@@ -19327,45 +19331,16 @@ const jsenvPluginProtocolFile = ({
19327
19331
  if (!urlInfo.url.startsWith("file:")) {
19328
19332
  return null;
19329
19333
  }
19330
- const { rootDirectoryUrl } = urlInfo.context;
19331
- const generateContent = () => {
19332
- const urlObject = new URL(urlInfo.url);
19333
- const { firstReference } = urlInfo;
19334
- if (firstReference.leadsToADirectory) {
19335
- const directoryContentArray = readdirSync(urlObject);
19336
- if (firstReference.type === "filesystem") {
19337
- const content = JSON.stringify(directoryContentArray, null, " ");
19338
- return {
19339
- type: "directory",
19340
- contentType: "application/json",
19341
- content,
19342
- };
19343
- }
19344
- const acceptsHtml = urlInfo.context.request
19345
- ? pickContentType(urlInfo.context.request, ["text/html"])
19346
- : false;
19347
- if (acceptsHtml) {
19348
- firstReference.expectedType = "html";
19349
- const directoryUrl = urlObject.href;
19350
- const directoryContentItems = generateDirectoryContentItems(
19351
- directoryUrl,
19352
- rootDirectoryUrl,
19353
- );
19354
- const html = generateHtmlForDirectory(directoryContentItems);
19355
- return {
19356
- type: "html",
19357
- contentType: "text/html",
19358
- content: html,
19359
- };
19360
- }
19361
- return {
19362
- type: "directory",
19363
- contentType: "application/json",
19364
- content: JSON.stringify(directoryContentArray, null, " "),
19365
- };
19366
- }
19367
- const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
19368
- const fileBuffer = readFileSync(urlObject);
19334
+ const { firstReference } = urlInfo;
19335
+ let { fsStat } = firstReference;
19336
+ if (!fsStat) {
19337
+ fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
19338
+ }
19339
+ const isDirectory = fsStat?.isDirectory();
19340
+ const { rootDirectoryUrl, request } = urlInfo.context;
19341
+ const serveFile = (url) => {
19342
+ const contentType = CONTENT_TYPE.fromUrlExtension(url);
19343
+ const fileBuffer = readFileSync(new URL(url));
19369
19344
  const content = CONTENT_TYPE.isTextual(contentType)
19370
19345
  ? String(fileBuffer)
19371
19346
  : fileBuffer;
@@ -19376,14 +19351,8 @@ const jsenvPluginProtocolFile = ({
19376
19351
  };
19377
19352
  };
19378
19353
 
19379
- const request = urlInfo.context.request;
19380
- if (request && request.headers["sec-fetch-dest"] === "document") {
19381
- try {
19382
- return generateContent();
19383
- } catch (e) {
19384
- if (e.code !== "ENOENT") {
19385
- throw e;
19386
- }
19354
+ if (!fsStat) {
19355
+ if (request && request.headers["sec-fetch-dest"] === "document") {
19387
19356
  const directoryContentItems = generateDirectoryContentItems(
19388
19357
  urlInfo.url,
19389
19358
  rootDirectoryUrl,
@@ -19403,7 +19372,40 @@ const jsenvPluginProtocolFile = ({
19403
19372
  };
19404
19373
  }
19405
19374
  }
19406
- return generateContent();
19375
+ if (isDirectory) {
19376
+ const directoryContentArray = readdirSync(new URL(urlInfo.url));
19377
+ if (firstReference.type === "filesystem") {
19378
+ const content = JSON.stringify(directoryContentArray, null, " ");
19379
+ return {
19380
+ type: "directory",
19381
+ contentType: "application/json",
19382
+ content,
19383
+ };
19384
+ }
19385
+ const acceptsHtml = request
19386
+ ? pickContentType(request, ["text/html"])
19387
+ : false;
19388
+ if (acceptsHtml) {
19389
+ firstReference.expectedType = "html";
19390
+ const directoryUrl = urlInfo.url;
19391
+ const directoryContentItems = generateDirectoryContentItems(
19392
+ directoryUrl,
19393
+ rootDirectoryUrl,
19394
+ );
19395
+ const html = generateHtmlForDirectory(directoryContentItems);
19396
+ return {
19397
+ type: "html",
19398
+ contentType: "text/html",
19399
+ content: html,
19400
+ };
19401
+ }
19402
+ return {
19403
+ type: "directory",
19404
+ contentType: "application/json",
19405
+ content: JSON.stringify(directoryContentArray, null, " "),
19406
+ };
19407
+ }
19408
+ return serveFile(urlInfo.url);
19407
19409
  },
19408
19410
  },
19409
19411
  ];
@@ -21122,6 +21124,19 @@ const getCorePlugins = ({
21122
21124
  directoryListingUrlMocks,
21123
21125
  }),
21124
21126
 
21127
+ {
21128
+ name: "jsenv:resolve_root_as_main",
21129
+ appliesDuring: "*",
21130
+ resolveReference: (reference) => {
21131
+ const { ownerUrlInfo } = reference;
21132
+ if (reference.specifier === "/") {
21133
+ const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
21134
+ const url = new URL(mainFilePath, rootDirectoryUrl);
21135
+ return url;
21136
+ }
21137
+ return null;
21138
+ },
21139
+ },
21125
21140
  ...(nodeEsmResolution
21126
21141
  ? [jsenvPluginNodeEsmResolution(nodeEsmResolution)]
21127
21142
  : []),
@@ -22865,7 +22880,7 @@ const build = async ({
22865
22880
  if (outDirectoryUrl === undefined) {
22866
22881
  if (
22867
22882
  process.env.CAPTURING_SIDE_EFFECTS ||
22868
- (!true)
22883
+ (false)
22869
22884
  ) {
22870
22885
  outDirectoryUrl = new URL("../.jsenv_b/", sourceDirectoryUrl);
22871
22886
  } else {
@@ -23742,7 +23757,7 @@ const startDevServer = async ({
23742
23757
  if (outDirectoryUrl === undefined) {
23743
23758
  if (
23744
23759
  process.env.CAPTURING_SIDE_EFFECTS ||
23745
- (!true)
23760
+ (false)
23746
23761
  ) {
23747
23762
  outDirectoryUrl = new URL("../.jsenv/", sourceDirectoryUrl);
23748
23763
  } else {
@@ -24052,12 +24067,14 @@ const startDevServer = async ({
24052
24067
  parentUrl,
24053
24068
  );
24054
24069
  if (!reference) {
24055
- reference =
24056
- kitchen.graph.rootUrlInfo.dependencies.createResolveAndFinalize({
24057
- trace: { message: parentUrl },
24058
- type: "http_request",
24059
- specifier: request.resource,
24060
- });
24070
+ const rootUrlInfo = kitchen.graph.rootUrlInfo;
24071
+ rootUrlInfo.context.request = request;
24072
+ reference = rootUrlInfo.dependencies.createResolveAndFinalize({
24073
+ trace: { message: parentUrl },
24074
+ type: "http_request",
24075
+ specifier: request.resource,
24076
+ });
24077
+ rootUrlInfo.context.request = null;
24061
24078
  }
24062
24079
  const urlInfo = reference.urlInfo;
24063
24080
  const ifNoneMatch = request.headers["if-none-match"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "39.9.4",
3
+ "version": "39.9.5",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -34,7 +34,7 @@
34
34
  "/src/"
35
35
  ],
36
36
  "volta": {
37
- "node": "22.3.0"
37
+ "node": "22.13.1"
38
38
  },
39
39
  "workspaces": [
40
40
  "./packages/independent/*",
@@ -69,17 +69,17 @@
69
69
  "dependencies": {
70
70
  "@financial-times/polyfill-useragent-normaliser": "1.10.2",
71
71
  "@jsenv/abort": "4.3.0",
72
- "@jsenv/ast": "6.4.1",
73
- "@jsenv/filesystem": "4.13.0",
72
+ "@jsenv/ast": "6.4.3",
73
+ "@jsenv/filesystem": "4.13.1",
74
74
  "@jsenv/humanize": "1.2.8",
75
75
  "@jsenv/importmap": "1.2.1",
76
76
  "@jsenv/integrity": "0.0.2",
77
- "@jsenv/js-module-fallback": "1.3.54",
77
+ "@jsenv/js-module-fallback": "1.3.55",
78
78
  "@jsenv/node-esm-resolution": "1.0.6",
79
- "@jsenv/plugin-bundling": "2.7.21",
80
- "@jsenv/plugin-minification": "1.5.12",
81
- "@jsenv/plugin-supervisor": "1.6.1",
82
- "@jsenv/plugin-transpilation": "1.4.89",
79
+ "@jsenv/plugin-bundling": "2.7.23",
80
+ "@jsenv/plugin-minification": "1.5.13",
81
+ "@jsenv/plugin-supervisor": "1.6.2",
82
+ "@jsenv/plugin-transpilation": "1.4.91",
83
83
  "@jsenv/runtime-compat": "1.3.1",
84
84
  "@jsenv/server": "15.3.3",
85
85
  "@jsenv/sourcemap": "1.2.29",
@@ -91,7 +91,6 @@
91
91
  "devDependencies": {
92
92
  "@babel/plugin-syntax-import-attributes": "7.26.0",
93
93
  "@babel/plugin-syntax-optional-chaining-assign": "7.25.9",
94
- "@eslint/compat": "1.2.4",
95
94
  "@jsenv/assert": "workspace:*",
96
95
  "@jsenv/cli": "workspace:*",
97
96
  "@jsenv/core": "./",
@@ -108,7 +107,7 @@
108
107
  "@playwright/browser-firefox": "1.49.1",
109
108
  "@playwright/browser-webkit": "1.49.1",
110
109
  "babel-plugin-transform-async-to-promises": "0.8.18",
111
- "eslint": "9.17.0",
110
+ "eslint": "9.18.0",
112
111
  "open": "10.1.0",
113
112
  "playwright": "1.49.1",
114
113
  "prettier": "3.4.2",
@@ -422,12 +422,14 @@ export const startDevServer = async ({
422
422
  parentUrl,
423
423
  );
424
424
  if (!reference) {
425
- reference =
426
- kitchen.graph.rootUrlInfo.dependencies.createResolveAndFinalize({
427
- trace: { message: parentUrl },
428
- type: "http_request",
429
- specifier: request.resource,
430
- });
425
+ const rootUrlInfo = kitchen.graph.rootUrlInfo;
426
+ rootUrlInfo.context.request = request;
427
+ reference = rootUrlInfo.dependencies.createResolveAndFinalize({
428
+ trace: { message: parentUrl },
429
+ type: "http_request",
430
+ specifier: request.resource,
431
+ });
432
+ rootUrlInfo.context.request = null;
431
433
  }
432
434
  const urlInfo = reference.urlInfo;
433
435
  const ifNoneMatch = request.headers["if-none-match"];
@@ -291,7 +291,7 @@ const createReference = ({
291
291
  isInline = false,
292
292
  content,
293
293
  contentType,
294
- leadsToADirectory = false,
294
+ fsStat = null,
295
295
  debug = false,
296
296
  original = null,
297
297
  prev = null,
@@ -352,7 +352,7 @@ const createReference = ({
352
352
  version,
353
353
  injected,
354
354
  timing: {},
355
- leadsToADirectory,
355
+ fsStat,
356
356
  debug,
357
357
  // for inline resources the reference contains the content
358
358
  isInline,
@@ -336,7 +336,7 @@ const createUrlInfo = (url, context) => {
336
336
  version: reference.version,
337
337
  content: reference.content,
338
338
  contentType: reference.contentType,
339
- leadsToADirectory: reference.leadsToADirectory,
339
+ fsStat: reference.fsStat,
340
340
  debug: reference.debug,
341
341
  importAttributes: reference.importAttributes,
342
342
  astInfo: reference.astInfo,
@@ -254,7 +254,7 @@ export const createUrlInfoTransformer = ({
254
254
  if (
255
255
  urlInfo.type === "directory" ||
256
256
  // happens when type is "html" to list directory content for example
257
- urlInfo.firstReference?.leadsToADirectory
257
+ urlInfo.firstReference?.fsStat?.isDirectory()
258
258
  ) {
259
259
  // no need to write the directory
260
260
  return;
@@ -65,7 +65,29 @@ export const initAutoreload = ({ mainFilePath }) => {
65
65
  currentExecution: null,
66
66
  reload: () => {
67
67
  const someEffectIsFullReload = reloader.changes.value.some(
68
- (reloadMessage) => reloadMessage.type === "full",
68
+ (reloadMessage) => {
69
+ if (reloadMessage.type === "full") {
70
+ return true;
71
+ }
72
+ if (reloadMessage.type === "hot") {
73
+ for (const reloadInstruction of reloadMessage.hotInstructions) {
74
+ if (reloadInstruction.type === "html") {
75
+ const acceptedByUrl = new URL(
76
+ reloadInstruction.acceptedBy,
77
+ `${window.location.origin}/`,
78
+ ).href;
79
+ const isCurrentHtmlFile = compareTwoUrlPaths(
80
+ acceptedByUrl,
81
+ window.location.href,
82
+ );
83
+ if (isCurrentHtmlFile) {
84
+ return true;
85
+ }
86
+ }
87
+ }
88
+ }
89
+ return false;
90
+ },
69
91
  );
70
92
  if (someEffectIsFullReload) {
71
93
  dispatchBeforeFullReload();
@@ -149,33 +171,35 @@ This could be due to syntax errors or importing non-existent modules (see errors
149
171
  // - code was not executed (code splitting with dynamic import)
150
172
  // - import.meta.hot.accept() is not called (happens for HTML and CSS)
151
173
  if (type === "prune") {
152
- if (urlHotMeta) {
153
- dispatchBeforePrune();
154
- delete urlHotMetas[urlToFetch];
155
- if (urlHotMeta.disposeCallback) {
156
- console.log(
157
- `[jsenv] cleanup ${boundary} (no longer referenced by ${acceptedBy})`,
158
- );
159
- if (debug) {
160
- console.log(`call dispose callback`);
161
- }
162
- await urlHotMeta.disposeCallback();
174
+ if (!urlHotMeta) {
175
+ // code not executed for this url, no need to prune
176
+ continue;
177
+ }
178
+ dispatchBeforePrune();
179
+ delete urlHotMetas[urlToFetch];
180
+ if (urlHotMeta.disposeCallback) {
181
+ console.log(
182
+ `[jsenv] cleanup ${boundary} (no longer referenced by ${acceptedBy})`,
183
+ );
184
+ if (debug) {
185
+ console.log(`call dispose callback`);
163
186
  }
187
+ await urlHotMeta.disposeCallback();
164
188
  }
165
189
  continue;
166
190
  }
167
- if (acceptedBy === boundary) {
168
- console.log(`[jsenv] hot reloading ${boundary} (${cause})`);
169
- } else {
170
- console.log(
171
- `[jsenv] hot reloading ${acceptedBy} usage in ${boundary} (${cause})`,
172
- );
173
- }
174
191
  if (type === "js_module") {
175
192
  if (!urlHotMeta) {
176
- // code was not executed, no need to re-execute it
193
+ // code not yet executed for this url, no need to re-execute it
177
194
  continue;
178
195
  }
196
+ if (acceptedBy === boundary) {
197
+ console.log(`[jsenv] hot reload ${boundary} (${cause})`);
198
+ } else {
199
+ console.log(
200
+ `[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
201
+ );
202
+ }
179
203
  if (urlHotMeta.disposeCallback) {
180
204
  if (debug) {
181
205
  console.log(`call dispose callback`);
@@ -211,9 +235,21 @@ This could be due to syntax errors or importing non-existent modules (see errors
211
235
  !isRootHtmlFile &&
212
236
  !compareTwoUrlPaths(urlToFetch, window.location.href)
213
237
  ) {
238
+ if (debug) {
239
+ console.log(
240
+ `[jsenv] skip ${acceptedBy} hot reload because we are not in that html page`,
241
+ );
242
+ }
214
243
  // we are not in that HTML page
215
244
  continue;
216
245
  }
246
+ if (acceptedBy === boundary) {
247
+ console.log(`[jsenv] hot reload ${boundary} (${cause})`);
248
+ } else {
249
+ console.log(
250
+ `[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
251
+ );
252
+ }
217
253
  const urlToReload = new URL(acceptedBy, `${window.location.origin}/`)
218
254
  .href;
219
255
  const domNodesUsingUrl = getDOMNodesUsingUrl(urlToReload);
@@ -22,7 +22,6 @@ export const jsenvPluginDirectoryReferenceEffect = (
22
22
  if (pathname[pathname.length - 1] !== "/") {
23
23
  return null;
24
24
  }
25
- reference.leadsToADirectory = true;
26
25
  reference.expectedType = "directory";
27
26
  if (reference.ownerUrlInfo.type === "directory") {
28
27
  reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
@@ -81,6 +81,19 @@ export const getCorePlugins = ({
81
81
  directoryListingUrlMocks,
82
82
  }),
83
83
 
84
+ {
85
+ name: "jsenv:resolve_root_as_main",
86
+ appliesDuring: "*",
87
+ resolveReference: (reference) => {
88
+ const { ownerUrlInfo } = reference;
89
+ if (reference.specifier === "/") {
90
+ const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
91
+ const url = new URL(mainFilePath, rootDirectoryUrl);
92
+ return url;
93
+ }
94
+ return null;
95
+ },
96
+ },
84
97
  ...(nodeEsmResolution
85
98
  ? [jsenvPluginNodeEsmResolution(nodeEsmResolution)]
86
99
  : []),
@@ -3,6 +3,7 @@ import {
3
3
  applyFileSystemMagicResolution,
4
4
  getExtensionsToTry,
5
5
  } from "@jsenv/node-esm-resolution";
6
+ import { urlToExtension, urlToPathname } from "@jsenv/urls";
6
7
  import { realpathSync } from "node:fs";
7
8
  import { pathToFileURL } from "node:url";
8
9
 
@@ -23,7 +24,6 @@ export const jsenvPluginFsRedirection = ({
23
24
  return null;
24
25
  }
25
26
  if (reference.url === "file:///" || reference.url === "file://") {
26
- reference.leadsToADirectory = true;
27
27
  return `ignore:file:///`;
28
28
  }
29
29
  // ignore all new URL second arg
@@ -38,27 +38,19 @@ export const jsenvPluginFsRedirection = ({
38
38
  // return `ignore:${reference.url}`;
39
39
  // }
40
40
  const urlObject = new URL(reference.url);
41
- let stat;
42
- try {
43
- stat = readEntryStatSync(urlObject);
44
- } catch (e) {
45
- if (e.code === "ENOENT") {
46
- stat = null;
47
- } else {
48
- throw e;
49
- }
50
- }
41
+ let fsStat = readEntryStatSync(urlObject, { nullIfNotFound: true });
42
+ reference.fsStat = fsStat;
51
43
  const { search, hash } = urlObject;
52
44
  urlObject.search = "";
53
45
  urlObject.hash = "";
54
- applyStatEffectsOnUrlObject(urlObject, stat);
46
+ applyFsStatEffectsOnUrlObject(urlObject, fsStat);
55
47
  const shouldApplyFilesystemMagicResolution =
56
48
  reference.type === "js_import";
57
49
  if (shouldApplyFilesystemMagicResolution) {
58
50
  const filesystemResolution = applyFileSystemMagicResolution(
59
51
  urlObject.href,
60
52
  {
61
- fileStat: stat,
53
+ fileStat: fsStat,
62
54
  magicDirectoryIndex,
63
55
  magicExtensions: getExtensionsToTry(
64
56
  magicExtensions,
@@ -67,12 +59,28 @@ export const jsenvPluginFsRedirection = ({
67
59
  },
68
60
  );
69
61
  if (filesystemResolution.stat) {
70
- stat = filesystemResolution.stat;
62
+ fsStat = filesystemResolution.stat;
63
+ reference.fsStat = fsStat;
71
64
  urlObject.href = filesystemResolution.url;
72
- applyStatEffectsOnUrlObject(urlObject, stat);
65
+ applyFsStatEffectsOnUrlObject(urlObject, fsStat);
73
66
  }
74
67
  }
75
- if (!stat) {
68
+ if (!fsStat) {
69
+ // for SPA we want to serve the root HTML file only when:
70
+ // 1. There is no corresponding file on the filesystem
71
+ // 2. The url pathname does not have an extension
72
+ // This point assume client is requesting a file when there is an extension
73
+ // and it assumes all routes will not use extension
74
+ // 3. The url pathname does not ends with "/"
75
+ // In that case we assume client explicitely asks to load a directory
76
+ if (
77
+ !urlToExtension(urlObject) &&
78
+ !urlToPathname(urlObject).endsWith("/")
79
+ ) {
80
+ const { mainFilePath, rootDirectoryUrl } =
81
+ reference.ownerUrlInfo.context;
82
+ return new URL(mainFilePath, rootDirectoryUrl);
83
+ }
76
84
  return null;
77
85
  }
78
86
  const urlBeforeSymlinkResolution = urlObject.href;
@@ -92,15 +100,19 @@ export const jsenvPluginFsRedirection = ({
92
100
  };
93
101
  };
94
102
 
95
- const applyStatEffectsOnUrlObject = (urlObject, stat) => {
103
+ const applyFsStatEffectsOnUrlObject = (urlObject, fsStat) => {
104
+ if (!fsStat) {
105
+ return;
106
+ }
96
107
  const { pathname } = urlObject;
97
108
  const pathnameUsesTrailingSlash = pathname.endsWith("/");
98
109
  // force trailing slash on directories
99
- if (stat && stat.isDirectory() && !pathnameUsesTrailingSlash) {
100
- urlObject.pathname = `${pathname}/`;
101
- }
102
- // otherwise remove trailing slash if any
103
- if (stat && !stat.isDirectory() && pathnameUsesTrailingSlash) {
110
+ if (fsStat.isDirectory()) {
111
+ if (!pathnameUsesTrailingSlash) {
112
+ urlObject.pathname = `${pathname}/`;
113
+ }
114
+ } else if (pathnameUsesTrailingSlash) {
115
+ // otherwise remove trailing slash if any
104
116
  // a warning here? (because it's strange to reference a file with a trailing slash)
105
117
  urlObject.pathname = pathname.slice(0, -1);
106
118
  }
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  assertAndNormalizeDirectoryUrl,
3
3
  comparePathnames,
4
+ readEntryStatSync,
4
5
  } from "@jsenv/filesystem";
5
6
  import { pickContentType } from "@jsenv/server";
6
7
  import {
@@ -84,45 +85,16 @@ export const jsenvPluginProtocolFile = ({
84
85
  if (!urlInfo.url.startsWith("file:")) {
85
86
  return null;
86
87
  }
87
- const { rootDirectoryUrl } = urlInfo.context;
88
- const generateContent = () => {
89
- const urlObject = new URL(urlInfo.url);
90
- const { firstReference } = urlInfo;
91
- if (firstReference.leadsToADirectory) {
92
- const directoryContentArray = readdirSync(urlObject);
93
- if (firstReference.type === "filesystem") {
94
- const content = JSON.stringify(directoryContentArray, null, " ");
95
- return {
96
- type: "directory",
97
- contentType: "application/json",
98
- content,
99
- };
100
- }
101
- const acceptsHtml = urlInfo.context.request
102
- ? pickContentType(urlInfo.context.request, ["text/html"])
103
- : false;
104
- if (acceptsHtml) {
105
- firstReference.expectedType = "html";
106
- const directoryUrl = urlObject.href;
107
- const directoryContentItems = generateDirectoryContentItems(
108
- directoryUrl,
109
- rootDirectoryUrl,
110
- );
111
- const html = generateHtmlForDirectory(directoryContentItems);
112
- return {
113
- type: "html",
114
- contentType: "text/html",
115
- content: html,
116
- };
117
- }
118
- return {
119
- type: "directory",
120
- contentType: "application/json",
121
- content: JSON.stringify(directoryContentArray, null, " "),
122
- };
123
- }
124
- const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
125
- const fileBuffer = readFileSync(urlObject);
88
+ const { firstReference } = urlInfo;
89
+ let { fsStat } = firstReference;
90
+ if (!fsStat) {
91
+ fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
92
+ }
93
+ const isDirectory = fsStat?.isDirectory();
94
+ const { rootDirectoryUrl, request } = urlInfo.context;
95
+ const serveFile = (url) => {
96
+ const contentType = CONTENT_TYPE.fromUrlExtension(url);
97
+ const fileBuffer = readFileSync(new URL(url));
126
98
  const content = CONTENT_TYPE.isTextual(contentType)
127
99
  ? String(fileBuffer)
128
100
  : fileBuffer;
@@ -133,14 +105,8 @@ export const jsenvPluginProtocolFile = ({
133
105
  };
134
106
  };
135
107
 
136
- const request = urlInfo.context.request;
137
- if (request && request.headers["sec-fetch-dest"] === "document") {
138
- try {
139
- return generateContent();
140
- } catch (e) {
141
- if (e.code !== "ENOENT") {
142
- throw e;
143
- }
108
+ if (!fsStat) {
109
+ if (request && request.headers["sec-fetch-dest"] === "document") {
144
110
  const directoryContentItems = generateDirectoryContentItems(
145
111
  urlInfo.url,
146
112
  rootDirectoryUrl,
@@ -160,7 +126,40 @@ export const jsenvPluginProtocolFile = ({
160
126
  };
161
127
  }
162
128
  }
163
- return generateContent();
129
+ if (isDirectory) {
130
+ const directoryContentArray = readdirSync(new URL(urlInfo.url));
131
+ if (firstReference.type === "filesystem") {
132
+ const content = JSON.stringify(directoryContentArray, null, " ");
133
+ return {
134
+ type: "directory",
135
+ contentType: "application/json",
136
+ content,
137
+ };
138
+ }
139
+ const acceptsHtml = request
140
+ ? pickContentType(request, ["text/html"])
141
+ : false;
142
+ if (acceptsHtml) {
143
+ firstReference.expectedType = "html";
144
+ const directoryUrl = urlInfo.url;
145
+ const directoryContentItems = generateDirectoryContentItems(
146
+ directoryUrl,
147
+ rootDirectoryUrl,
148
+ );
149
+ const html = generateHtmlForDirectory(directoryContentItems);
150
+ return {
151
+ type: "html",
152
+ contentType: "text/html",
153
+ content: html,
154
+ };
155
+ }
156
+ return {
157
+ type: "directory",
158
+ contentType: "application/json",
159
+ content: JSON.stringify(directoryContentArray, null, " "),
160
+ };
161
+ }
162
+ return serveFile(urlInfo.url);
164
163
  },
165
164
  },
166
165
  ];
@@ -156,11 +156,7 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
156
156
  } else {
157
157
  position = getHtmlNodeAttributePosition(node, attributeName);
158
158
  }
159
- const {
160
- line,
161
- column,
162
- // originalLine, originalColumn
163
- } = position;
159
+ const { line, column, originalLine, originalColumn } = position;
164
160
  const debug =
165
161
  getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
166
162
 
@@ -193,8 +189,9 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
193
189
  subtype,
194
190
  expectedType,
195
191
  specifier: attributeValue,
196
- specifierLine: line,
197
- specifierColumn: column,
192
+ specifierLine: originalLine === undefined ? line : originalLine,
193
+ specifierColumn:
194
+ originalColumn === undefined ? column : originalColumn,
198
195
  specifierStart: attributeValueStart,
199
196
  specifierEnd: attributeValueEnd,
200
197
  isResourceHint,
@@ -33,11 +33,6 @@ export const createNodeEsmResolver = ({
33
33
  return reference.specifier;
34
34
  }
35
35
  const { ownerUrlInfo } = reference;
36
- if (reference.specifier === "/") {
37
- const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
38
- const url = new URL(mainFilePath, rootDirectoryUrl);
39
- return url;
40
- }
41
36
  if (reference.specifier[0] === "/") {
42
37
  const url = new URL(
43
38
  reference.specifier.slice(1),
@@ -4,11 +4,6 @@ export const jsenvPluginWebResolution = () => {
4
4
  appliesDuring: "*",
5
5
  resolveReference: (reference) => {
6
6
  const { ownerUrlInfo } = reference;
7
- if (reference.specifier === "/") {
8
- const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
9
- const url = new URL(mainFilePath, rootDirectoryUrl);
10
- return url;
11
- }
12
7
  if (reference.specifier[0] === "/") {
13
8
  const url = new URL(
14
9
  reference.specifier.slice(1),
@@ -19,7 +14,9 @@ export const jsenvPluginWebResolution = () => {
19
14
  // baseUrl happens second argument to new URL() is different from
20
15
  // import.meta.url or document.currentScript.src
21
16
  const parentUrl =
22
- reference.baseUrl || ownerUrlInfo.originalUrl || ownerUrlInfo.url;
17
+ reference.baseUrl || ownerUrlInfo.context.dev
18
+ ? ownerUrlInfo.url
19
+ : ownerUrlInfo.originalUrl || ownerUrlInfo.url;
23
20
  const url = new URL(reference.specifier, parentUrl);
24
21
  return url;
25
22
  },