@jsenv/core 36.0.2 → 36.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,10 +13,11 @@ import http from "node:http";
13
13
  import { Readable, Stream, Writable } from "node:stream";
14
14
  import { Http2ServerResponse } from "node:http2";
15
15
  import { lookup } from "node:dns";
16
- import { SOURCEMAP, generateSourcemapFileUrl, composeTwoSourcemaps, generateSourcemapDataUrl, createMagicSource, getOriginalPosition } from "@jsenv/sourcemap";
16
+ import { SOURCEMAP, generateSourcemapFileUrl, composeTwoSourcemaps, generateSourcemapDataUrl, createMagicSource } from "@jsenv/sourcemap";
17
17
  import { parseHtmlString, visitHtmlNodes, getHtmlNodeAttribute, analyzeScriptNode, stringifyHtmlAst, parseSrcSet, getHtmlNodeText, setHtmlNodeAttributes, getHtmlNodePosition, getHtmlNodeAttributePosition, removeHtmlNodeText, setHtmlNodeText, parseCssUrls, parseJsUrls, applyBabelPlugins, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, injectJsImport, analyzeLinkNode, injectHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
18
18
  import { createRequire } from "node:module";
19
19
  import babelParser from "@babel/parser";
20
+ import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
20
21
 
21
22
  /*
22
23
  * data:[<mediatype>][;base64],<data>
@@ -7290,8 +7291,6 @@ const generateAccessControlHeaders = ({
7290
7291
  };
7291
7292
  };
7292
7293
 
7293
- new Map();
7294
-
7295
7294
  const lookupPackageDirectory = currentUrl => {
7296
7295
  if (currentUrl === "file:///") {
7297
7296
  return null;
@@ -7806,7 +7805,6 @@ const createUrlInfo = url => {
7806
7805
  originalUrl: undefined,
7807
7806
  filename: "",
7808
7807
  isEntryPoint: false,
7809
- mustIgnore: undefined,
7810
7808
  originalContent: undefined,
7811
7809
  content: undefined,
7812
7810
  sourcemap: null,
@@ -7972,7 +7970,7 @@ const createPluginController = kitchenContext => {
7972
7970
  if (info.timing) {
7973
7971
  info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] = performance$1.now() - startTimestamp;
7974
7972
  }
7975
- valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned);
7973
+ valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned, info);
7976
7974
  return valueReturned;
7977
7975
  };
7978
7976
  const callAsyncHook = async (hook, info, context) => {
@@ -7993,7 +7991,7 @@ const createPluginController = kitchenContext => {
7993
7991
  if (info.timing) {
7994
7992
  info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] = performance$1.now() - startTimestamp;
7995
7993
  }
7996
- valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned);
7994
+ valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned, info);
7997
7995
  return valueReturned;
7998
7996
  };
7999
7997
  const callHooks = (hookName, info, context, callback) => {
@@ -8085,7 +8083,7 @@ info = {}) => {
8085
8083
  }
8086
8084
  return hookValue;
8087
8085
  };
8088
- const assertAndNormalizeReturnValue = (hookName, returnValue) => {
8086
+ const assertAndNormalizeReturnValue = (hookName, returnValue, info) => {
8089
8087
  // all hooks are allowed to return null/undefined as a signal of "I don't do anything"
8090
8088
  if (returnValue === null || returnValue === undefined) {
8091
8089
  return returnValue;
@@ -8094,7 +8092,7 @@ const assertAndNormalizeReturnValue = (hookName, returnValue) => {
8094
8092
  if (!returnValueAssertion.appliesTo.includes(hookName)) {
8095
8093
  continue;
8096
8094
  }
8097
- const assertionResult = returnValueAssertion.assertion(returnValue);
8095
+ const assertionResult = returnValueAssertion.assertion(returnValue, info);
8098
8096
  if (assertionResult !== undefined) {
8099
8097
  // normalization
8100
8098
  returnValue = assertionResult;
@@ -8118,7 +8116,7 @@ const returnValueAssertions = [{
8118
8116
  }, {
8119
8117
  name: "content_assertion",
8120
8118
  appliesTo: ["fetchUrlContent", "transformUrlContent", "finalizeUrlContent", "optimizeUrlContent"],
8121
- assertion: valueReturned => {
8119
+ assertion: (valueReturned, urlInfo) => {
8122
8120
  if (typeof valueReturned === "string" || Buffer.isBuffer(valueReturned)) {
8123
8121
  return {
8124
8122
  content: valueReturned
@@ -8126,11 +8124,10 @@ const returnValueAssertions = [{
8126
8124
  }
8127
8125
  if (typeof valueReturned === "object") {
8128
8126
  const {
8129
- mustIgnore,
8130
8127
  content,
8131
8128
  body
8132
8129
  } = valueReturned;
8133
- if (mustIgnore) {
8130
+ if (urlInfo.url.startsWith("ignore:")) {
8134
8131
  return undefined;
8135
8132
  }
8136
8133
  if (typeof content !== "string" && !Buffer.isBuffer(content) && !body) {
@@ -9102,6 +9099,9 @@ const createKitchen = ({
9102
9099
  logLevel,
9103
9100
  rootDirectoryUrl,
9104
9101
  mainFilePath,
9102
+ ignore,
9103
+ ignoreProtocol = "remove",
9104
+ supportedProtocols = ["file:", "data:", "virtual:", "http:", "https:"],
9105
9105
  urlGraph,
9106
9106
  dev = false,
9107
9107
  build = false,
@@ -9147,6 +9147,35 @@ const createKitchen = ({
9147
9147
  plugins.forEach(pluginEntry => {
9148
9148
  pluginController.pushPlugin(pluginEntry);
9149
9149
  });
9150
+ const isIgnoredByProtocol = url => {
9151
+ const {
9152
+ protocol
9153
+ } = new URL(url);
9154
+ const protocolIsSupported = supportedProtocols.some(supportedProtocol => protocol === supportedProtocol);
9155
+ return !protocolIsSupported;
9156
+ };
9157
+ let isIgnoredByParam = () => false;
9158
+ if (ignore) {
9159
+ const associations = URL_META.resolveAssociations({
9160
+ ignore
9161
+ }, rootDirectoryUrl);
9162
+ const cache = new Map();
9163
+ isIgnoredByParam = url => {
9164
+ const fromCache = cache.get(url);
9165
+ if (fromCache) return fromCache;
9166
+ const {
9167
+ ignore
9168
+ } = URL_META.applyAssociations({
9169
+ url,
9170
+ associations
9171
+ });
9172
+ cache.set(url, ignore);
9173
+ return ignore;
9174
+ };
9175
+ }
9176
+ const isIgnored = url => {
9177
+ return isIgnoredByProtocol(url) || isIgnoredByParam(url);
9178
+ };
9150
9179
 
9151
9180
  /*
9152
9181
  * - "http_request"
@@ -9192,7 +9221,6 @@ const createKitchen = ({
9192
9221
  specifierColumn,
9193
9222
  baseUrl,
9194
9223
  isOriginalPosition,
9195
- mustIgnore,
9196
9224
  isEntryPoint = false,
9197
9225
  isResourceHint = false,
9198
9226
  isImplicit = false,
@@ -9241,7 +9269,6 @@ const createKitchen = ({
9241
9269
  specifierColumn,
9242
9270
  isOriginalPosition,
9243
9271
  baseUrl,
9244
- mustIgnore,
9245
9272
  isEntryPoint,
9246
9273
  isResourceHint,
9247
9274
  isImplicit,
@@ -9286,13 +9313,29 @@ const createKitchen = ({
9286
9313
  url = normalizeUrl(url);
9287
9314
  let referencedUrlObject;
9288
9315
  let searchParams;
9289
- const onReferenceUrlChange = referenceUrl => {
9316
+ const setReferenceUrl = referenceUrl => {
9317
+ // ignored urls are prefixed with "ignore:" so that reference are associated
9318
+ // to a dedicated urlInfo that is ignored.
9319
+ // this way it's only once a resource is referenced by reference that is not ignored
9320
+ // that the resource is cooked
9321
+ if (reference.specifier[0] === "#" &&
9322
+ // For Html, css and "#" refer to a resource in the page, reference must be preserved
9323
+ // However for js import specifiers they have a different meaning and we want
9324
+ // to resolve them (https://nodejs.org/api/packages.html#imports for instance)
9325
+ reference.type !== "js_import") {
9326
+ referenceUrl = `ignore:${referenceUrl}`;
9327
+ } else if (isIgnored(referenceUrl)) {
9328
+ referenceUrl = `ignore:${referenceUrl}`;
9329
+ }
9330
+ if (referenceUrl.startsWith("ignore:") && !reference.specifier.startsWith("ignore:")) {
9331
+ reference.specifier = `ignore:${reference.specifier}`;
9332
+ }
9290
9333
  referencedUrlObject = new URL(referenceUrl);
9291
9334
  searchParams = referencedUrlObject.searchParams;
9292
9335
  reference.url = referenceUrl;
9293
9336
  reference.searchParams = searchParams;
9294
9337
  };
9295
- onReferenceUrlChange(url);
9338
+ setReferenceUrl(url);
9296
9339
  if (reference.debug) {
9297
9340
  logger.debug(`url resolved by "${pluginController.getLastPluginUsed().name}"
9298
9341
  ${ANSI.color(reference.specifier, ANSI.GREY)} ->
@@ -9314,7 +9357,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
9314
9357
  ...reference
9315
9358
  };
9316
9359
  updateReference(prevReference, reference);
9317
- onReferenceUrlChange(normalizedReturnValue);
9360
+ setReferenceUrl(normalizedReturnValue);
9318
9361
  });
9319
9362
  reference.generatedUrl = reference.url;
9320
9363
  const urlInfo = urlGraph.reuseOrCreateUrlInfo(reference.url);
@@ -9333,7 +9376,10 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
9333
9376
  reference.generatedUrl = normalizeUrl(referencedUrlObject.href);
9334
9377
  });
9335
9378
  const returnValue = pluginController.callHooksUntil("formatReference", reference, referenceContext);
9336
- if (reference.mustIgnore) {
9379
+ if (reference.url.startsWith("ignore:")) {
9380
+ if (ignoreProtocol === "remove") {
9381
+ reference.specifier = reference.specifier.slice("ignore:".length);
9382
+ }
9337
9383
  reference.generatedSpecifier = reference.specifier;
9338
9384
  reference.generatedSpecifier = urlSpecifierEncoding.encode(reference);
9339
9385
  } else {
@@ -9509,7 +9555,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
9509
9555
  contextDuringFetch: context
9510
9556
  });
9511
9557
  };
9512
- if (!urlInfo.mustIgnore) {
9558
+ if (!urlInfo.url.startsWith("ignore:")) {
9513
9559
  // references
9514
9560
  const references = [];
9515
9561
  context.referenceUtils = {
@@ -9839,11 +9885,6 @@ const traceFromUrlSite = urlSite => {
9839
9885
  };
9840
9886
  };
9841
9887
  const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
9842
- if (reference.mustIgnore) {
9843
- urlInfo.mustIgnore = true;
9844
- } else {
9845
- urlInfo.mustIgnore = false;
9846
- }
9847
9888
  urlInfo.originalUrl = urlInfo.originalUrl || reference.url;
9848
9889
  if (reference.isEntryPoint || isWebWorkerEntryPointReference(reference)) {
9849
9890
  urlInfo.isEntryPoint = true;
@@ -10075,15 +10116,19 @@ const createUrlGraphReport = urlGraph => {
10075
10116
  total: 0
10076
10117
  };
10077
10118
  urlGraph.urlInfoMap.forEach(urlInfo => {
10078
- if (urlInfo.url.startsWith("data:")) {
10079
- return;
10080
- }
10081
10119
  // ignore:
10082
- // - inline files: they are already taken into account in the file where they appear
10083
10120
  // - ignored files: we don't know their content
10084
- if (urlInfo.isInline || urlInfo.mustIgnore) {
10121
+ // - inline files and data files: they are already taken into account in the file where they appear
10122
+ if (urlInfo.url.startsWith("ignore:")) {
10085
10123
  return;
10086
10124
  }
10125
+ if (urlInfo.isInline) {
10126
+ return;
10127
+ }
10128
+ if (urlInfo.url.startsWith("data:")) {
10129
+ return;
10130
+ }
10131
+
10087
10132
  // file loaded via import assertion are already inside the graph
10088
10133
  // their js module equivalent are ignored to avoid counting it twice
10089
10134
  // in the build graph the file targeted by import assertion will likely be gone
@@ -11111,19 +11156,12 @@ const parseAndTransformJsReferences = async (urlInfo, context, {
11111
11156
  };
11112
11157
 
11113
11158
  const jsenvPluginReferenceAnalysis = ({
11114
- include,
11115
- supportedProtocols = ["file:", "data:", "virtual:", "http:", "https:"],
11116
- ignoreProtocol = "remove",
11117
11159
  inlineContent = true,
11118
11160
  inlineConvertedScript = false,
11119
11161
  fetchInlineUrls = true,
11120
11162
  allowEscapeForVersioning = false
11121
11163
  }) => {
11122
- return [jsenvPluginReferenceAnalysisInclude({
11123
- include,
11124
- supportedProtocols,
11125
- ignoreProtocol
11126
- }), jsenvPluginDirectoryReferenceAnalysis(), jsenvPluginHtmlReferenceAnalysis({
11164
+ return [jsenvPluginDirectoryReferenceAnalysis(), jsenvPluginHtmlReferenceAnalysis({
11127
11165
  inlineContent,
11128
11166
  inlineConvertedScript
11129
11167
  }), jsenvPluginWebmanifestReferenceAnalysis(), jsenvPluginCssReferenceAnalysis(), jsenvPluginJsReferenceAnalysis({
@@ -11131,78 +11169,6 @@ const jsenvPluginReferenceAnalysis = ({
11131
11169
  allowEscapeForVersioning
11132
11170
  }), ...(inlineContent ? [jsenvPluginDataUrlsAnalysis()] : []), ...(inlineContent && fetchInlineUrls ? [jsenvPluginInlineContentFetcher()] : []), jsenvPluginReferenceExpectedTypes()];
11133
11171
  };
11134
- const jsenvPluginReferenceAnalysisInclude = ({
11135
- include,
11136
- supportedProtocols,
11137
- ignoreProtocol
11138
- }) => {
11139
- // eslint-disable-next-line no-unused-vars
11140
- let getIncludeInfo = url => undefined;
11141
- return {
11142
- name: "jsenv:reference_analysis_include",
11143
- appliesDuring: "*",
11144
- init: ({
11145
- rootDirectoryUrl
11146
- }) => {
11147
- if (include) {
11148
- const associations = URL_META.resolveAssociations({
11149
- include
11150
- }, rootDirectoryUrl);
11151
- getIncludeInfo = url => {
11152
- const {
11153
- include
11154
- } = URL_META.applyAssociations({
11155
- url,
11156
- associations
11157
- });
11158
- return include;
11159
- };
11160
- }
11161
- },
11162
- redirectReference: reference => {
11163
- if (reference.mustIgnore !== undefined) {
11164
- return;
11165
- }
11166
- if (reference.specifier[0] === "#" &&
11167
- // For Html, css and in general "#" refer to a resource in the page
11168
- // so that urls must be kept intact
11169
- // However for js import specifiers they have a different meaning and we want
11170
- // to resolve them (https://nodejs.org/api/packages.html#imports for instance)
11171
- reference.type !== "js_import") {
11172
- reference.mustIgnore = true;
11173
- return;
11174
- }
11175
- if (reference.url.startsWith("ignore:")) {
11176
- reference.mustIgnore = true;
11177
- if (ignoreProtocol === "remove") {
11178
- reference.specifier = reference.specifier.slice("ignore:".length);
11179
- }
11180
- return;
11181
- }
11182
- const includeInfo = getIncludeInfo(reference.url);
11183
- if (includeInfo === true) {
11184
- reference.mustIgnore = false;
11185
- return;
11186
- }
11187
- if (includeInfo === false) {
11188
- reference.mustIgnore = true;
11189
- return;
11190
- }
11191
- const {
11192
- protocol
11193
- } = new URL(reference.url);
11194
- const protocolIsSupported = supportedProtocols.some(supportedProtocol => protocol === supportedProtocol);
11195
- if (!protocolIsSupported) {
11196
- reference.mustIgnore = true;
11197
- }
11198
- },
11199
- formatReference: reference => {
11200
- if (ignoreProtocol === "inject" && reference.mustIgnore && !reference.url.startsWith("ignore:")) {
11201
- reference.specifier = `ignore:${reference.specifier}`;
11202
- }
11203
- }
11204
- };
11205
- };
11206
11172
  const jsenvPluginInlineContentFetcher = () => {
11207
11173
  return {
11208
11174
  name: "jsenv:inline_content_fetcher",
@@ -17561,6 +17527,19 @@ const jsenvPluginProtocolFile = ({
17561
17527
  if (reference.isInline) {
17562
17528
  return null;
17563
17529
  }
17530
+ // ignore root file url
17531
+ if (reference.url === "file:///" || reference.url === "file://") {
17532
+ reference.leadsToADirectory = true;
17533
+ return `ignore:file:///`;
17534
+ }
17535
+ // ignore "./" on new URL("./")
17536
+ if (reference.subtype === "new_url_first_arg" && reference.specifier === "./") {
17537
+ return `ignore:${reference.url}`;
17538
+ }
17539
+ // ignore all new URL second arg
17540
+ if (reference.subtype === "new_url_second_arg") {
17541
+ return `ignore:${reference.url}`;
17542
+ }
17564
17543
  const urlObject = new URL(reference.url);
17565
17544
  let stat;
17566
17545
  try {
@@ -17582,6 +17561,7 @@ const jsenvPluginProtocolFile = ({
17582
17561
  const pathnameUsesTrailingSlash = pathname.endsWith("/");
17583
17562
  urlObject.search = "";
17584
17563
  urlObject.hash = "";
17564
+
17585
17565
  // force trailing slash on directories
17586
17566
  if (stat && stat.isDirectory() && !pathnameUsesTrailingSlash) {
17587
17567
  urlObject.pathname = `${pathname}/`;
@@ -17592,33 +17572,24 @@ const jsenvPluginProtocolFile = ({
17592
17572
  urlObject.pathname = pathname.slice(0, -1);
17593
17573
  }
17594
17574
  let url = urlObject.href;
17595
- const mustIgnore = stat && stat.isDirectory() && (
17596
- // ignore new URL second arg
17597
- reference.subtype === "new_url_second_arg" ||
17598
- // ignore root file url
17599
- reference.url === "file:///" || reference.subtype === "new_url_first_arg" && reference.specifier === "./");
17600
- if (mustIgnore) {
17601
- reference.mustIgnore = true;
17602
- } else {
17603
- const shouldApplyDilesystemMagicResolution = reference.type === "js_import";
17604
- if (shouldApplyDilesystemMagicResolution) {
17605
- const filesystemResolution = applyFileSystemMagicResolution(url, {
17606
- fileStat: stat,
17607
- magicDirectoryIndex,
17608
- magicExtensions: getExtensionsToTry(magicExtensions, reference.parentUrl)
17609
- });
17610
- if (filesystemResolution.stat) {
17611
- stat = filesystemResolution.stat;
17612
- url = filesystemResolution.url;
17613
- }
17575
+ const shouldApplyDilesystemMagicResolution = reference.type === "js_import";
17576
+ if (shouldApplyDilesystemMagicResolution) {
17577
+ const filesystemResolution = applyFileSystemMagicResolution(url, {
17578
+ fileStat: stat,
17579
+ magicDirectoryIndex,
17580
+ magicExtensions: getExtensionsToTry(magicExtensions, reference.parentUrl)
17581
+ });
17582
+ if (filesystemResolution.stat) {
17583
+ stat = filesystemResolution.stat;
17584
+ url = filesystemResolution.url;
17614
17585
  }
17615
- if (stat && stat.isDirectory()) {
17616
- const directoryAllowed = reference.type === "filesystem" || typeof directoryReferenceAllowed === "function" && directoryReferenceAllowed(reference) || directoryReferenceAllowed;
17617
- if (!directoryAllowed) {
17618
- const error = new Error("Reference leads to a directory");
17619
- error.code = "DIRECTORY_REFERENCE_NOT_ALLOWED";
17620
- throw error;
17621
- }
17586
+ }
17587
+ if (stat && stat.isDirectory()) {
17588
+ const directoryAllowed = reference.type === "filesystem" || typeof directoryReferenceAllowed === "function" && directoryReferenceAllowed(reference) || directoryReferenceAllowed;
17589
+ if (!directoryAllowed) {
17590
+ const error = new Error("Reference leads to a directory");
17591
+ error.code = "DIRECTORY_REFERENCE_NOT_ALLOWED";
17592
+ throw error;
17622
17593
  }
17623
17594
  }
17624
17595
  reference.leadsToADirectory = stat && stat.isDirectory();
@@ -17706,710 +17677,12 @@ const jsenvPluginProtocolHttp = () => {
17706
17677
  name: "jsenv:protocol_http",
17707
17678
  appliesDuring: "*",
17708
17679
  redirectReference: reference => {
17709
- if (reference.url.startsWith("http:") || reference.url.startsWith("https:")) {
17710
- reference.mustIgnore = true;
17711
- }
17712
17680
  // TODO: according to some pattern matching jsenv could be allowed
17713
17681
  // to fetch and transform http urls
17714
- }
17715
- };
17716
- };
17717
-
17718
- /*
17719
- * ```js
17720
- * console.log(42)
17721
- * ```
17722
- * becomes
17723
- * ```js
17724
- * window.__supervisor__.jsClassicStart('main.html@L10-L13.js')
17725
- * try {
17726
- * console.log(42)
17727
- * window.__supervisor__.jsClassicEnd('main.html@L10-L13.js')
17728
- * } catch(e) {
17729
- * window.__supervisor__.jsClassicError('main.html@L10-L13.js', e)
17730
- * }
17731
- * ```
17732
- *
17733
- * ```js
17734
- * import value from "./file.js"
17735
- * console.log(value)
17736
- * ```
17737
- * becomes
17738
- * ```js
17739
- * window.__supervisor__.jsModuleStart('main.html@L10-L13.js')
17740
- * try {
17741
- * const value = await import("./file.js")
17742
- * console.log(value)
17743
- * window.__supervisor__.jsModuleEnd('main.html@L10-L13.js')
17744
- * } catch(e) {
17745
- * window.__supervisor__.jsModuleError('main.html@L10-L13.js', e)
17746
- * }
17747
- * ```
17748
- *
17749
- * -> TO KEEP IN MIND:
17750
- * Static import can throw errors like
17751
- * The requested module '/js_module_export_not_found/foo.js' does not provide an export named 'answerr'
17752
- * While dynamic import will work just fine
17753
- * and create a variable named "undefined"
17754
- */
17755
-
17756
- const injectSupervisorIntoJs = async ({
17757
- webServer,
17758
- content,
17759
- url,
17760
- type,
17761
- inlineSrc
17762
- }) => {
17763
- const babelPluginJsSupervisor = type === "js_module" ? babelPluginJsModuleSupervisor : babelPluginJsClassicSupervisor;
17764
- const result = await applyBabelPlugins({
17765
- urlInfo: {
17766
- content,
17767
- originalUrl: url,
17768
- type
17769
- },
17770
- babelPlugins: [[babelPluginJsSupervisor, {
17771
- inlineSrc
17772
- }]]
17773
- });
17774
- let code = result.code;
17775
- let map = result.map;
17776
- const sourcemapDataUrl = generateSourcemapDataUrl(map);
17777
- code = SOURCEMAP.writeComment({
17778
- contentType: "text/javascript",
17779
- content: code,
17780
- specifier: sourcemapDataUrl
17781
- });
17782
- code = `${code}
17783
- //# sourceURL=${urlToRelativeUrl(url, webServer.rootDirectoryUrl)}`;
17784
- return code;
17785
- };
17786
- const babelPluginJsModuleSupervisor = babel => {
17787
- const t = babel.types;
17788
- return {
17789
- name: "js-module-supervisor",
17790
- visitor: {
17791
- Program: (programPath, state) => {
17792
- const {
17793
- inlineSrc
17794
- } = state.opts;
17795
- if (state.file.metadata.jsExecutionInstrumented) return;
17796
- state.file.metadata.jsExecutionInstrumented = true;
17797
- const urlNode = t.stringLiteral(inlineSrc);
17798
- const startCallNode = createSupervisionCall({
17799
- t,
17800
- urlNode,
17801
- methodName: "jsModuleStart"
17802
- });
17803
- const endCallNode = createSupervisionCall({
17804
- t,
17805
- urlNode,
17806
- methodName: "jsModuleEnd"
17807
- });
17808
- const errorCallNode = createSupervisionCall({
17809
- t,
17810
- urlNode,
17811
- methodName: "jsModuleError",
17812
- args: [t.identifier("e")]
17813
- });
17814
- const bodyPath = programPath.get("body");
17815
- const importNodes = [];
17816
- const topLevelNodes = [];
17817
- for (const topLevelNodePath of bodyPath) {
17818
- const topLevelNode = topLevelNodePath.node;
17819
- if (t.isImportDeclaration(topLevelNode)) {
17820
- importNodes.push(topLevelNode);
17821
- } else {
17822
- topLevelNodes.push(topLevelNode);
17823
- }
17824
- }
17825
-
17826
- // replace all import nodes with dynamic imports
17827
- const dynamicImports = [];
17828
- importNodes.forEach(importNode => {
17829
- const dynamicImportConversion = convertStaticImportIntoDynamicImport(importNode, t);
17830
- if (Array.isArray(dynamicImportConversion)) {
17831
- dynamicImports.push(...dynamicImportConversion);
17832
- } else {
17833
- dynamicImports.push(dynamicImportConversion);
17834
- }
17835
- });
17836
- const tryCatchNode = t.tryStatement(t.blockStatement([...dynamicImports, ...topLevelNodes, endCallNode]), t.catchClause(t.identifier("e"), t.blockStatement([errorCallNode])));
17837
- programPath.replaceWith(t.program([startCallNode, tryCatchNode]));
17838
- }
17839
- }
17840
- };
17841
- };
17842
- const convertStaticImportIntoDynamicImport = (staticImportNode, t) => {
17843
- const awaitExpression = t.awaitExpression(t.callExpression(t.import(), [t.stringLiteral(staticImportNode.source.value)]));
17844
-
17845
- // import "./file.js" -> await import("./file.js")
17846
- if (staticImportNode.specifiers.length === 0) {
17847
- return t.expressionStatement(awaitExpression);
17848
- }
17849
- if (staticImportNode.specifiers.length === 1) {
17850
- const [firstSpecifier] = staticImportNode.specifiers;
17851
- if (firstSpecifier.type === "ImportNamespaceSpecifier") {
17852
- return t.variableDeclaration("const", [t.variableDeclarator(t.identifier(firstSpecifier.local.name), awaitExpression)]);
17853
- }
17854
- }
17855
- if (staticImportNode.specifiers.length === 2) {
17856
- const [first, second] = staticImportNode.specifiers;
17857
- if (first.type === "ImportDefaultSpecifier" && second.type === "ImportNamespaceSpecifier") {
17858
- const namespaceDeclaration = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(second.local.name), awaitExpression)]);
17859
- const defaultDeclaration = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(first.local.name), t.memberExpression(t.identifier(second.local.name), t.identifier("default")))]);
17860
- return [namespaceDeclaration, defaultDeclaration];
17861
- }
17862
- }
17863
-
17864
- // import { name } from "./file.js" -> const { name } = await import("./file.js")
17865
- // import toto, { name } from "./file.js" -> const { name, default as toto } = await import("./file.js")
17866
- const objectPattern = t.objectPattern(staticImportNode.specifiers.map(specifier => {
17867
- if (specifier.type === "ImportDefaultSpecifier") {
17868
- return t.objectProperty(t.identifier("default"), t.identifier(specifier.local.name), false,
17869
- // computed
17870
- false // shorthand
17871
- );
17872
- }
17873
- // if (specifier.type === "ImportNamespaceSpecifier") {
17874
- // return t.restElement(t.identifier(specifier.local.name))
17875
- // }
17876
- const isRenamed = specifier.imported.name !== specifier.local.name;
17877
- if (isRenamed) {
17878
- return t.objectProperty(t.identifier(specifier.imported.name), t.identifier(specifier.local.name), false,
17879
- // computed
17880
- false // shorthand
17881
- );
17882
- }
17883
- // shorthand must be true
17884
- return t.objectProperty(t.identifier(specifier.local.name), t.identifier(specifier.local.name), false,
17885
- // computed
17886
- true // shorthand
17887
- );
17888
- }));
17889
-
17890
- const variableDeclarator = t.variableDeclarator(objectPattern, awaitExpression);
17891
- const variableDeclaration = t.variableDeclaration("const", [variableDeclarator]);
17892
- return variableDeclaration;
17893
- };
17894
- const babelPluginJsClassicSupervisor = babel => {
17895
- const t = babel.types;
17896
- return {
17897
- name: "js-classic-supervisor",
17898
- visitor: {
17899
- Program: (programPath, state) => {
17900
- const {
17901
- inlineSrc
17902
- } = state.opts;
17903
- if (state.file.metadata.jsExecutionInstrumented) return;
17904
- state.file.metadata.jsExecutionInstrumented = true;
17905
- const urlNode = t.stringLiteral(inlineSrc);
17906
- const startCallNode = createSupervisionCall({
17907
- t,
17908
- urlNode,
17909
- methodName: "jsClassicStart"
17910
- });
17911
- const endCallNode = createSupervisionCall({
17912
- t,
17913
- urlNode,
17914
- methodName: "jsClassicEnd"
17915
- });
17916
- const errorCallNode = createSupervisionCall({
17917
- t,
17918
- urlNode,
17919
- methodName: "jsClassicError",
17920
- args: [t.identifier("e")]
17921
- });
17922
- const topLevelNodes = programPath.node.body;
17923
- const tryCatchNode = t.tryStatement(t.blockStatement([...topLevelNodes, endCallNode]), t.catchClause(t.identifier("e"), t.blockStatement([errorCallNode])));
17924
- programPath.replaceWith(t.program([startCallNode, tryCatchNode]));
17925
- }
17926
- }
17927
- };
17928
- };
17929
- const createSupervisionCall = ({
17930
- t,
17931
- methodName,
17932
- urlNode,
17933
- args = []
17934
- }) => {
17935
- return t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.identifier("window"), t.identifier("__supervisor__")), t.identifier(methodName)), [urlNode, ...args]), [], null);
17936
- };
17937
-
17938
- /*
17939
- * Jsenv needs to track js execution in order to:
17940
- * 1. report errors
17941
- * 2. wait for all js execution inside an HTML page before killing the browser
17942
- *
17943
- * A naive approach would rely on "load" events on window but:
17944
- * scenario | covered by window "load"
17945
- * ------------------------------------------- | -------------------------
17946
- * js referenced by <script src> | yes
17947
- * js inlined into <script> | yes
17948
- * js referenced by <script type="module" src> | partially (not for import and top level await)
17949
- * js inlined into <script type="module"> | not at all
17950
- * Same for "error" event on window who is not enough
17951
- *
17952
- * <script src="file.js">
17953
- * becomes
17954
- * <script>
17955
- * window.__supervisor__.superviseScript('file.js')
17956
- * </script>
17957
- *
17958
- * <script>
17959
- * console.log(42)
17960
- * </script>
17961
- * becomes
17962
- * <script inlined-from-src="main.html@L10-C5.js">
17963
- * window.__supervisor.__superviseScript("main.html@L10-C5.js")
17964
- * </script>
17965
- *
17966
- * <script type="module" src="module.js"></script>
17967
- * becomes
17968
- * <script type="module">
17969
- * window.__supervisor__.superviseScriptTypeModule('module.js')
17970
- * </script>
17971
- *
17972
- * <script type="module">
17973
- * console.log(42)
17974
- * </script>
17975
- * becomes
17976
- * <script type="module" inlined-from-src="main.html@L10-C5.js">
17977
- * window.__supervisor__.superviseScriptTypeModule('main.html@L10-C5.js')
17978
- * </script>
17979
- *
17980
- * Why Inline scripts are converted to files dynamically?
17981
- * -> No changes required on js source code, it's only the HTML that is modified
17982
- * - Also allow to catch syntax errors and export missing
17983
- */
17984
-
17985
- const supervisorFileUrl$1 = new URL("./js/supervisor.js", import.meta.url).href;
17986
- const injectSupervisorIntoHTML = async ({
17987
- content,
17988
- url
17989
- }, {
17990
- supervisorScriptSrc = supervisorFileUrl$1,
17991
- supervisorOptions,
17992
- webServer,
17993
- onInlineScript = () => {},
17994
- generateInlineScriptSrc = ({
17995
- inlineScriptUrl
17996
- }) => urlToRelativeUrl(inlineScriptUrl, webServer.rootDirectoryUrl),
17997
- inlineAsRemote
17998
- }) => {
17999
- const htmlAst = parseHtmlString(content);
18000
- const mutations = [];
18001
- const actions = [];
18002
- const scriptInfos = [];
18003
- // 1. Find inline and remote scripts
18004
- {
18005
- const handleInlineScript = (scriptNode, {
18006
- type,
18007
- extension,
18008
- textContent
18009
- }) => {
18010
- const {
18011
- line,
18012
- column,
18013
- lineEnd,
18014
- columnEnd,
18015
- isOriginal
18016
- } = getHtmlNodePosition(scriptNode, {
18017
- preferOriginal: true
18018
- });
18019
- const inlineScriptUrl = generateInlineContentUrl({
18020
- url,
18021
- extension: extension || ".js",
18022
- line,
18023
- column,
18024
- lineEnd,
18025
- columnEnd
18026
- });
18027
- const inlineScriptSrc = generateInlineScriptSrc({
18028
- type,
18029
- textContent,
18030
- inlineScriptUrl,
18031
- isOriginal,
18032
- line,
18033
- column
18034
- });
18035
- onInlineScript({
18036
- type,
18037
- textContent,
18038
- url: inlineScriptUrl,
18039
- isOriginal,
18040
- line,
18041
- column,
18042
- src: inlineScriptSrc
18043
- });
18044
- if (inlineAsRemote) {
18045
- // prefere la version src
18046
- scriptInfos.push({
18047
- type,
18048
- src: inlineScriptSrc
18049
- });
18050
- const remoteJsSupervised = generateCodeToSuperviseScriptWithSrc({
18051
- type,
18052
- src: inlineScriptSrc
18053
- });
18054
- mutations.push(() => {
18055
- setHtmlNodeText(scriptNode, remoteJsSupervised, {
18056
- indentation: "auto"
18057
- });
18058
- setHtmlNodeAttributes(scriptNode, {
18059
- "jsenv-cooked-by": "jsenv:supervisor",
18060
- "src": undefined,
18061
- "inlined-from-src": inlineScriptSrc
18062
- });
18063
- });
18064
- } else {
18065
- scriptInfos.push({
18066
- type,
18067
- src: inlineScriptSrc,
18068
- isInline: true
18069
- });
18070
- actions.push(async () => {
18071
- try {
18072
- const inlineJsSupervised = await injectSupervisorIntoJs({
18073
- webServer,
18074
- content: textContent,
18075
- url: inlineScriptUrl,
18076
- type,
18077
- inlineSrc: inlineScriptSrc
18078
- });
18079
- mutations.push(() => {
18080
- setHtmlNodeText(scriptNode, inlineJsSupervised, {
18081
- indentation: "auto"
18082
- });
18083
- setHtmlNodeAttributes(scriptNode, {
18084
- "jsenv-cooked-by": "jsenv:supervisor"
18085
- });
18086
- });
18087
- } catch (e) {
18088
- if (e.code === "PARSE_ERROR") {
18089
- // mutations.push(() => {
18090
- // setHtmlNodeAttributes(scriptNode, {
18091
- // "jsenv-cooked-by": "jsenv:supervisor",
18092
- // })
18093
- // })
18094
- // on touche a rien
18095
- return;
18096
- }
18097
- throw e;
18098
- }
18099
- });
18100
- }
18101
- };
18102
- const handleScriptWithSrc = (scriptNode, {
18103
- type,
18104
- src
18105
- }) => {
18106
- scriptInfos.push({
18107
- type,
18108
- src
18109
- });
18110
- const remoteJsSupervised = generateCodeToSuperviseScriptWithSrc({
18111
- type,
18112
- src
18113
- });
18114
- mutations.push(() => {
18115
- setHtmlNodeText(scriptNode, remoteJsSupervised, {
18116
- indentation: "auto"
18117
- });
18118
- setHtmlNodeAttributes(scriptNode, {
18119
- "jsenv-cooked-by": "jsenv:supervisor",
18120
- "src": undefined,
18121
- "inlined-from-src": src
18122
- });
18123
- });
18124
- };
18125
- visitHtmlNodes(htmlAst, {
18126
- script: scriptNode => {
18127
- const {
18128
- type,
18129
- extension
18130
- } = analyzeScriptNode(scriptNode);
18131
- if (type !== "js_classic" && type !== "js_module") {
18132
- return;
18133
- }
18134
- if (getHtmlNodeAttribute(scriptNode, "jsenv-injected-by")) {
18135
- return;
18136
- }
18137
- const noSupervisor = getHtmlNodeAttribute(scriptNode, "no-supervisor");
18138
- if (noSupervisor !== undefined) {
18139
- return;
18140
- }
18141
- const scriptNodeText = getHtmlNodeText(scriptNode);
18142
- if (scriptNodeText) {
18143
- handleInlineScript(scriptNode, {
18144
- type,
18145
- extension,
18146
- textContent: scriptNodeText
18147
- });
18148
- return;
18149
- }
18150
- const src = getHtmlNodeAttribute(scriptNode, "src");
18151
- if (src) {
18152
- const urlObject = new URL(src, "http://example.com");
18153
- if (urlObject.searchParams.has("inline")) {
18154
- return;
18155
- }
18156
- handleScriptWithSrc(scriptNode, {
18157
- type,
18158
- src
18159
- });
18160
- return;
18161
- }
18162
- }
18163
- });
18164
- }
18165
- // 2. Inject supervisor js file + setup call
18166
- {
18167
- const setupParamsSource = stringifyParams({
18168
- ...supervisorOptions,
18169
- serverIsJsenvDevServer: webServer.isJsenvDevServer,
18170
- rootDirectoryUrl: webServer.rootDirectoryUrl,
18171
- scriptInfos
18172
- }, " ");
18173
- injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
18174
- tagName: "script",
18175
- textContent: `window.__supervisor__.setup({${setupParamsSource}})`
18176
- }), "jsenv:supervisor");
18177
- injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
18178
- tagName: "script",
18179
- src: supervisorScriptSrc
18180
- }), "jsenv:supervisor");
18181
- }
18182
- // 3. Perform actions (transforming inline script content) and html mutations
18183
- if (actions.length > 0) {
18184
- await Promise.all(actions.map(action => action()));
18185
- }
18186
- mutations.forEach(mutation => mutation());
18187
- const htmlModified = stringifyHtmlAst(htmlAst);
18188
- return {
18189
- content: htmlModified
18190
- };
18191
- };
18192
- const stringifyParams = (params, prefix = "") => {
18193
- const source = JSON.stringify(params, null, prefix);
18194
- if (prefix.length) {
18195
- // remove leading "{\n"
18196
- // remove leading prefix
18197
- // remove trailing "\n}"
18198
- return source.slice(2 + prefix.length, -2);
18199
- }
18200
- // remove leading "{"
18201
- // remove trailing "}"
18202
- return source.slice(1, -1);
18203
- };
18204
- const generateCodeToSuperviseScriptWithSrc = ({
18205
- type,
18206
- src
18207
- }) => {
18208
- const srcEncoded = JSON.stringify(src);
18209
- if (type === "js_module") {
18210
- return `window.__supervisor__.superviseScriptTypeModule(${srcEncoded}, (url) => import(url));`;
18211
- }
18212
- return `window.__supervisor__.superviseScript(${srcEncoded});`;
18213
- };
18214
-
18215
- /*
18216
- * This plugin provides a way for jsenv to know when js execution is done
18217
- */
18218
-
18219
- const supervisorFileUrl = new URL("./js/supervisor.js", import.meta.url).href;
18220
- const jsenvPluginSupervisor = ({
18221
- logs = false,
18222
- measurePerf = false,
18223
- errorOverlay = true,
18224
- openInEditor = true,
18225
- errorBaseUrl
18226
- }) => {
18227
- return {
18228
- name: "jsenv:supervisor",
18229
- appliesDuring: "dev",
18230
- serve: async (request, context) => {
18231
- if (request.pathname.startsWith("/__get_code_frame__/")) {
18232
- const {
18233
- pathname,
18234
- searchParams
18235
- } = new URL(request.url);
18236
- let urlWithLineAndColumn = pathname.slice("/__get_code_frame__/".length);
18237
- urlWithLineAndColumn = decodeURIComponent(urlWithLineAndColumn);
18238
- const match = urlWithLineAndColumn.match(/:([0-9]+):([0-9]+)$/);
18239
- if (!match) {
18240
- return {
18241
- status: 400,
18242
- body: "Missing line and column in url"
18243
- };
18244
- }
18245
- const file = urlWithLineAndColumn.slice(0, match.index);
18246
- let line = parseInt(match[1]);
18247
- let column = parseInt(match[2]);
18248
- const urlInfo = context.urlGraph.getUrlInfo(file);
18249
- if (!urlInfo) {
18250
- return {
18251
- status: 204,
18252
- headers: {
18253
- "cache-control": "no-store"
18254
- }
18255
- };
18256
- }
18257
- const remap = searchParams.has("remap");
18258
- if (remap) {
18259
- const sourcemap = urlInfo.sourcemap;
18260
- if (sourcemap) {
18261
- const original = getOriginalPosition({
18262
- sourcemap,
18263
- url: file,
18264
- line,
18265
- column
18266
- });
18267
- if (original.line !== null) {
18268
- line = original.line;
18269
- if (original.column !== null) {
18270
- column = original.column;
18271
- }
18272
- }
18273
- }
18274
- }
18275
- const codeFrame = stringifyUrlSite({
18276
- url: file,
18277
- line,
18278
- column,
18279
- content: urlInfo.originalContent
18280
- });
18281
- return {
18282
- status: 200,
18283
- headers: {
18284
- "cache-control": "no-store",
18285
- "content-type": "text/plain",
18286
- "content-length": Buffer.byteLength(codeFrame)
18287
- },
18288
- body: codeFrame
18289
- };
18290
- }
18291
- if (request.pathname.startsWith("/__get_error_cause__/")) {
18292
- let file = request.pathname.slice("/__get_error_cause__/".length);
18293
- file = decodeURIComponent(file);
18294
- if (!file) {
18295
- return {
18296
- status: 400,
18297
- body: "Missing file in url"
18298
- };
18299
- }
18300
- const getErrorCauseInfo = () => {
18301
- const urlInfo = context.urlGraph.getUrlInfo(file);
18302
- if (!urlInfo) {
18303
- return null;
18304
- }
18305
- const {
18306
- error
18307
- } = urlInfo;
18308
- if (error) {
18309
- return error;
18310
- }
18311
- // search in direct dependencies (404 or 500)
18312
- const {
18313
- dependencies
18314
- } = urlInfo;
18315
- for (const dependencyUrl of dependencies) {
18316
- const dependencyUrlInfo = context.urlGraph.getUrlInfo(dependencyUrl);
18317
- if (dependencyUrlInfo.error) {
18318
- return dependencyUrlInfo.error;
18319
- }
18320
- }
18321
- return null;
18322
- };
18323
- const causeInfo = getErrorCauseInfo();
18324
- const body = JSON.stringify(causeInfo ? {
18325
- code: causeInfo.code,
18326
- message: causeInfo.message,
18327
- reason: causeInfo.reason,
18328
- stack: errorBaseUrl ? `stack mocked for snapshot` : causeInfo.stack,
18329
- codeFrame: causeInfo.traceMessage
18330
- } : null, null, " ");
18331
- return {
18332
- status: 200,
18333
- headers: {
18334
- "cache-control": "no-store",
18335
- "content-type": "application/json",
18336
- "content-length": Buffer.byteLength(body)
18337
- },
18338
- body
18339
- };
18340
- }
18341
- if (request.pathname.startsWith("/__open_in_editor__/")) {
18342
- let file = request.pathname.slice("/__open_in_editor__/".length);
18343
- file = decodeURIComponent(file);
18344
- if (!file) {
18345
- return {
18346
- status: 400,
18347
- body: "Missing file in url"
18348
- };
18349
- }
18350
- const launch = requireFromJsenv("launch-editor");
18351
- launch(fileURLToPath(file), () => {
18352
- // ignore error for now
18353
- });
18354
- return {
18355
- status: 200,
18356
- headers: {
18357
- "cache-control": "no-store"
18358
- }
18359
- };
17682
+ if (reference.url.startsWith("http:") || reference.url.startsWith("https:")) {
17683
+ return `ignore:${reference.url}`;
18360
17684
  }
18361
17685
  return null;
18362
- },
18363
- transformUrlContent: {
18364
- html: ({
18365
- url,
18366
- content
18367
- }, context) => {
18368
- const [supervisorFileReference] = context.referenceUtils.inject({
18369
- type: "script",
18370
- expectedType: "js_classic",
18371
- specifier: supervisorFileUrl
18372
- });
18373
- return injectSupervisorIntoHTML({
18374
- content,
18375
- url
18376
- }, {
18377
- supervisorScriptSrc: supervisorFileReference.generatedSpecifier,
18378
- supervisorOptions: {
18379
- errorBaseUrl,
18380
- logs,
18381
- measurePerf,
18382
- errorOverlay,
18383
- openInEditor
18384
- },
18385
- webServer: {
18386
- rootDirectoryUrl: context.rootDirectoryUrl,
18387
- isJsenvDevServer: true
18388
- },
18389
- inlineAsRemote: true,
18390
- generateInlineScriptSrc: ({
18391
- type,
18392
- textContent,
18393
- inlineScriptUrl,
18394
- isOriginal,
18395
- line,
18396
- column
18397
- }) => {
18398
- const [inlineScriptReference] = context.referenceUtils.foundInline({
18399
- type: "script",
18400
- subtype: "inline",
18401
- expectedType: type,
18402
- isOriginalPosition: isOriginal,
18403
- specifierLine: line - 1,
18404
- specifierColumn: column,
18405
- specifier: inlineScriptUrl,
18406
- contentType: "text/javascript",
18407
- content: textContent
18408
- });
18409
- return inlineScriptReference.generatedSpecifier;
18410
- }
18411
- });
18412
- }
18413
17686
  }
18414
17687
  };
18415
17688
  };
@@ -21332,6 +20605,7 @@ const build = async ({
21332
20605
  buildDirectoryUrl,
21333
20606
  entryPoints = {},
21334
20607
  assetsDirectory = "",
20608
+ ignore,
21335
20609
  runtimeCompat = defaultRuntimeCompat,
21336
20610
  base = runtimeCompat.node ? "./" : "/",
21337
20611
  plugins = [],
@@ -21469,6 +20743,10 @@ build ${entryPointKeys.length} entry points`);
21469
20743
  signal,
21470
20744
  logLevel,
21471
20745
  rootDirectoryUrl: sourceDirectoryUrl,
20746
+ ignore,
20747
+ // during first pass (craft) we keep "ignore:" when a reference is ignored
20748
+ // so that the second pass (shape) properly ignore those urls
20749
+ ignoreProtocol: "keep",
21472
20750
  urlGraph: rawGraph,
21473
20751
  build: true,
21474
20752
  runtimeCompat,
@@ -21484,12 +20762,7 @@ build ${entryPointKeys.length} entry points`);
21484
20762
  rootDirectoryUrl: sourceDirectoryUrl,
21485
20763
  urlGraph: rawGraph,
21486
20764
  runtimeCompat,
21487
- referenceAnalysis: {
21488
- ...referenceAnalysis,
21489
- // during first pass (craft) we inject "ignore:" when a reference must be ignored
21490
- // so that the second pass (shape) properly ignore those urls
21491
- ignoreProtocol: "inject"
21492
- },
20765
+ referenceAnalysis,
21493
20766
  nodeEsmResolution,
21494
20767
  magicExtensions,
21495
20768
  magicDirectoryIndex,
@@ -21528,20 +20801,21 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21528
20801
  const finalGraphKitchen = createKitchen({
21529
20802
  logLevel,
21530
20803
  rootDirectoryUrl: buildDirectoryUrl,
20804
+ // here most plugins are not there
20805
+ // - no external plugin
20806
+ // - no plugin putting reference.mustIgnore on https urls
20807
+ // At this stage it's only about redirecting urls to the build directory
20808
+ // consequently only a subset or urls are supported
20809
+ supportedProtocols: ["file:", "data:", "virtual:", "ignore:"],
20810
+ ignore,
20811
+ ignoreProtocol: versioning ? "keep" : "remove",
21531
20812
  urlGraph: finalGraph,
21532
20813
  build: true,
21533
20814
  runtimeCompat,
21534
20815
  ...contextSharedDuringBuild,
21535
20816
  plugins: [jsenvPluginReferenceAnalysis({
21536
20817
  ...referenceAnalysis,
21537
- // here most plugins are not there
21538
- // - no external plugin
21539
- // - no plugin putting reference.mustIgnore on https urls
21540
- // At this stage it's only about redirecting urls to the build directory
21541
- // consequently only a subset or urls are supported
21542
- supportedProtocols: ["file:", "data:", "virtual:", "ignore:"],
21543
- fetchInlineUrls: false,
21544
- ignoreProtocol: versioning ? "keep" : "remove"
20818
+ fetchInlineUrls: false
21545
20819
  }), ...(lineBreakNormalization ? [jsenvPluginLineBreakNormalization()] : []), jsenvPluginJsModuleFallback({
21546
20820
  systemJsInjection: true
21547
20821
  }), jsenvPluginInlining(), {
@@ -22109,14 +21383,11 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22109
21383
  const contentVersionMap = new Map();
22110
21384
  const hashCallbacks = [];
22111
21385
  GRAPH.forEach(finalGraph, urlInfo => {
22112
- if (urlInfo.url.startsWith("data:")) {
22113
- return;
22114
- }
22115
21386
  if (urlInfo.type === "sourcemap") {
22116
21387
  return;
22117
21388
  }
22118
21389
  // ignore:
22119
- // - inline files:
21390
+ // - inline files and data files:
22120
21391
  // they are already taken into account in the file where they appear
22121
21392
  // - ignored files:
22122
21393
  // we don't know their content
@@ -22128,7 +21399,10 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22128
21399
  if (urlInfo.isInline) {
22129
21400
  return;
22130
21401
  }
22131
- if (urlInfo.mustIgnore) {
21402
+ if (urlInfo.url.startsWith("data:")) {
21403
+ return;
21404
+ }
21405
+ if (urlInfo.url.startsWith("ignore:")) {
22132
21406
  return;
22133
21407
  }
22134
21408
  if (urlInfo.dependents.size === 0 && !urlInfo.isEntryPoint) {
@@ -22154,7 +21428,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22154
21428
  const dependencyContentVersion = contentVersionMap.get(reference.url);
22155
21429
  if (!dependencyContentVersion) {
22156
21430
  // no content generated for this dependency
22157
- // (inline, data:, sourcemap, mustIgnore is true, ...)
21431
+ // (inline, data:, ignore:, sourcemap, ...)
22158
21432
  return null;
22159
21433
  }
22160
21434
  if (preferWithoutVersioning(reference)) {
@@ -22213,20 +21487,14 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22213
21487
  const versioningKitchen = createKitchen({
22214
21488
  logLevel: logger.level,
22215
21489
  rootDirectoryUrl: buildDirectoryUrl,
21490
+ ignore,
21491
+ ignoreProtocol: "remove",
22216
21492
  urlGraph: finalGraph,
22217
21493
  build: true,
22218
21494
  runtimeCompat,
22219
21495
  ...contextSharedDuringBuild,
22220
- plugins: [
22221
- // here most plugins are not there
22222
- // - no external plugin
22223
- // - no plugin putting reference.mustIgnore on https urls
22224
- // At this stage it's only about versioning urls
22225
- // consequently only a subset or urls are supported
22226
- jsenvPluginReferenceAnalysis({
21496
+ plugins: [jsenvPluginReferenceAnalysis({
22227
21497
  ...referenceAnalysis,
22228
- supportedProtocols: ["file:", "data:", "virtual:"],
22229
- ignoreProtocol: "remove",
22230
21498
  fetchInlineUrls: false,
22231
21499
  inlineConvertedScript: true,
22232
21500
  // to be able to version their urls
@@ -22260,10 +21528,13 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22260
21528
  return url;
22261
21529
  },
22262
21530
  formatReference: reference => {
22263
- if (reference.mustIgnore) {
21531
+ if (reference.url.startsWith("ignore:")) {
22264
21532
  return null;
22265
21533
  }
22266
- if (reference.isInline || reference.url.startsWith("data:")) {
21534
+ if (reference.isInline) {
21535
+ return null;
21536
+ }
21537
+ if (reference.url.startsWith("data:")) {
22267
21538
  return null;
22268
21539
  }
22269
21540
  if (reference.isResourceHint) {
@@ -22275,9 +21546,6 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22275
21546
  if (!canUseVersionedUrl(referencedUrlInfo)) {
22276
21547
  return reference.specifier;
22277
21548
  }
22278
- if (referencedUrlInfo.mustIgnore) {
22279
- return null;
22280
- }
22281
21549
  const versionedUrl = versionedUrlMap.get(reference.url);
22282
21550
  if (!versionedUrl) {
22283
21551
  // happens for sourcemap
@@ -22385,9 +21653,6 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22385
21653
  }
22386
21654
  {
22387
21655
  GRAPH.forEach(finalGraph, urlInfo => {
22388
- if (urlInfo.mustIgnore) {
22389
- return;
22390
- }
22391
21656
  if (!urlInfo.url.startsWith("file:")) {
22392
21657
  return;
22393
21658
  }
@@ -22534,10 +21799,10 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22534
21799
  if (serviceWorkerEntryUrlInfos.length > 0) {
22535
21800
  const serviceWorkerResources = {};
22536
21801
  GRAPH.forEach(finalGraph, urlInfo => {
22537
- if (urlInfo.isInline || urlInfo.mustIgnore) {
21802
+ if (!urlInfo.url.startsWith("file:")) {
22538
21803
  return;
22539
21804
  }
22540
- if (!urlInfo.url.startsWith("file:")) {
21805
+ if (urlInfo.isInline) {
22541
21806
  return;
22542
21807
  }
22543
21808
  if (!canUseVersionedUrl(urlInfo)) {
@@ -22593,9 +21858,6 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22593
21858
  return buildRelativeUrl;
22594
21859
  };
22595
21860
  GRAPH.forEach(finalGraph, urlInfo => {
22596
- if (urlInfo.mustIgnore) {
22597
- return;
22598
- }
22599
21861
  if (!urlInfo.url.startsWith("file:")) {
22600
21862
  return;
22601
21863
  }
@@ -22860,6 +22122,7 @@ const createFileService = ({
22860
22122
  contextCache,
22861
22123
  sourceDirectoryUrl,
22862
22124
  sourceMainFilePath,
22125
+ ignore,
22863
22126
  sourceFilesConfig,
22864
22127
  runtimeCompat,
22865
22128
  plugins,
@@ -22932,6 +22195,7 @@ const createFileService = ({
22932
22195
  logLevel,
22933
22196
  rootDirectoryUrl: sourceDirectoryUrl,
22934
22197
  mainFilePath: sourceMainFilePath,
22198
+ ignore,
22935
22199
  urlGraph,
22936
22200
  dev: true,
22937
22201
  runtimeCompat,
@@ -23072,7 +22336,7 @@ const createFileService = ({
23072
22336
  return responseFromPlugin;
23073
22337
  }
23074
22338
  let reference;
23075
- const parentUrl = inferParentFromRequest(request, sourceDirectoryUrl);
22339
+ const parentUrl = inferParentFromRequest(request, sourceDirectoryUrl, sourceMainFilePath);
23076
22340
  if (parentUrl) {
23077
22341
  reference = urlGraph.inferReference(request.resource, parentUrl);
23078
22342
  }
@@ -23230,7 +22494,7 @@ const createFileService = ({
23230
22494
  }
23231
22495
  };
23232
22496
  };
23233
- const inferParentFromRequest = (request, sourceDirectoryUrl) => {
22497
+ const inferParentFromRequest = (request, sourceDirectoryUrl, sourceMainFilePath) => {
23234
22498
  const {
23235
22499
  referer
23236
22500
  } = request.headers;
@@ -23240,7 +22504,11 @@ const inferParentFromRequest = (request, sourceDirectoryUrl) => {
23240
22504
  const refererUrlObject = new URL(referer);
23241
22505
  refererUrlObject.searchParams.delete("hmr");
23242
22506
  refererUrlObject.searchParams.delete("v");
23243
- return WEB_URL_CONVERTER.asFileUrl(referer, {
22507
+ let refererUrl = refererUrlObject.href;
22508
+ if (refererUrl === `${request.origin}/`) {
22509
+ refererUrl = new URL(sourceMainFilePath, request.origin).href;
22510
+ }
22511
+ return WEB_URL_CONVERTER.asFileUrl(refererUrl, {
23244
22512
  origin: request.origin,
23245
22513
  rootDirectoryUrl: sourceDirectoryUrl
23246
22514
  });
@@ -23257,6 +22525,7 @@ const inferParentFromRequest = (request, sourceDirectoryUrl) => {
23257
22525
  const startDevServer = async ({
23258
22526
  sourceDirectoryUrl,
23259
22527
  sourceMainFilePath = "./index.html",
22528
+ ignore,
23260
22529
  port = 3456,
23261
22530
  hostname,
23262
22531
  acceptAnyIp,
@@ -23395,6 +22664,7 @@ const startDevServer = async ({
23395
22664
  contextCache,
23396
22665
  sourceDirectoryUrl,
23397
22666
  sourceMainFilePath,
22667
+ ignore,
23398
22668
  sourceFilesConfig,
23399
22669
  runtimeCompat,
23400
22670
  plugins,