From 589fa3c4fb2ac67fbec210b5cea1f1102c0fdd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Sun, 17 Jul 2022 11:54:58 +0200 Subject: [PATCH 1/6] Unset the top-level module fetch flag in dynamic imports The the top-level module fetch is only used in two steps of "fetch a single module script": - Step 9, where it only has effect if descrination is "worker", "sharedworker" or "serviceworker" (but for dynamic imports it's always "script") - Step 11, where it only has effect if there are custom "perform the fetch" steps, but "fetch an import() module script graph" is never called with custom "perform the fetch" steps. --- source | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source b/source index d19f245ffd9..8b2480bb4fa 100644 --- a/source +++ b/source @@ -95855,10 +95855,11 @@ document.querySelector("button").addEventListener("click", bound); sequence containing the response body. isTopLevel will be true for all classic script fetches, and for the initial fetch when fetching an external module script graph, fetching a module worker script graph, or fetching an import() module script graph, but false for the fetches - resulting from import statements encountered throughout the graph.

+ script graph">fetching an external module script graph, or fetching a module worker script graph, but false for the fetches + resulting from import statements encountered throughout the graph or from + fetching an import() module script + graph.

By default, not supplying a perform the fetch hook will cause the below algorithms to simply fetch @@ -96182,7 +96183,7 @@ document.querySelector("button").addEventListener("click", bound);

  • Fetch a single module script given url, settings object, "script", options, settings object, - "client", moduleRequest, true, and with the following steps + "client", moduleRequest, false, and with the following steps given result:

      From 7e80f33bd8db59be2f5cecbc71bcbf95b1018fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Sun, 17 Jul 2022 12:55:48 +0200 Subject: [PATCH 2/6] Implement `HostLoadImportedModule` hook * Implement `HostLoadImportedModule` hook. This commit also removes the `HostImportModuleDynamically` and `HostResolveImportedModule` hooks. * Differentiate fetch referrer between static and dynamic imports * Propagate custom perform the fetch steps through LoadRequestedModules * Review by annevk * Review by domenic --- source | 622 ++++++++++++++++++--------------------------------------- 1 file changed, 192 insertions(+), 430 deletions(-) diff --git a/source b/source index 8b2480bb4fa..0e2463416b3 100644 --- a/source +++ b/source @@ -2755,6 +2755,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
    1. a promise resolved with
    2. a promise rejected with
    3. upon rejection
    4. +
    5. upon fulfillment
    6. [LegacyFactoryFunction]
    7. [LegacyLenientThis]
    8. [LegacyNullToEmptyString]
    9. @@ -2886,8 +2887,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
    10. The Script Record specification type
    11. The Cyclic Module Record specification type
    12. The Source Text Module Record specification type and its - Evaluate and - Link methods
    13. + Evaluate, + Link and + LoadRequestedModules methods
    14. The ArrayCreate abstract operation
    15. The Call abstract operation
    16. @@ -2901,6 +2903,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
    17. The DetachArrayBuffer abstract operation
    18. The EnumerableOwnProperties abstract operation
    19. The FinishDynamicImport abstract operation
    20. +
    21. The FinishLoadingImportedModule abstract operation
    22. The OrdinaryFunctionCreate abstract operation
    23. The Get abstract operation
    24. The GetActiveScriptOrModule abstract operation
    25. @@ -2911,10 +2914,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
    26. The HostEnqueuePromiseJob abstract operation
    27. The HostEnsureCanAddPrivateElement abstract operation
    28. The HostEnsureCanCompileStrings abstract operation
    29. -
    30. The HostImportModuleDynamically abstract operation
    31. +
    32. The HostLoadImportedModule abstract operation
    33. The HostMakeJobCallback abstract operation
    34. The HostPromiseRejectionTracker abstract operation
    35. -
    36. The HostResolveImportedModule abstract operation
    37. The InitializeHostDefinedRealm abstract operation
    38. The IsAccessorDescriptor abstract operation
    39. The IsCallable abstract operation
    40. @@ -95858,8 +95860,7 @@ document.querySelector("button").addEventListener("click", bound); script graph">fetching an external module script graph, or fetching a module worker script graph, but false for the fetches resulting from import statements encountered throughout the graph or from - fetching an import() module script - graph.

      + import() expressions.

      By default, not supplying a perform the fetch hook will cause the below algorithms to simply fetch @@ -96143,58 +96144,9 @@ document.querySelector("button").addEventListener("click", bound);

    41. If result is null, run onComplete given null, and abort these steps.

    42. -
    43. Let visited set be « (url, "javascript") - ».

    44. -
    45. Fetch the descendants of and link result given settings object, "script", visited set, and onComplete.

    46. -
    -
  • - - -

    To fetch an import() module script graph given a moduleRequest, a - script, a settings object, some options, and an - onComplete algorithm, run these steps. onComplete must be an algorithm - accepting null (on failure) or a module script (on success).

    - -
      -
    1. Disallow further import maps given settings object.

    2. - -
    3. Let url be the result of resolving a - module specifier given script and moduleRequest.[[Specifier]], - catching any exceptions.

    4. - -
    5. If the previous step threw an exception, then run onComplete given null, and - return.

    6. - -
    7. Assert: moduleRequest.[[Assertions]] does not contain any - Record entry such that entry.[[Key]] is not "type", because we only asked for "type" assertions in - HostGetSupportedImportAssertions.

    8. - -
    9. Let moduleType be the result of running the module type from module - request steps given moduleRequest.

    10. - -
    11. If the result of running the module type allowed steps given - moduleType and settings object is false, then run onComplete - given null, and return.

    12. - -
    13. -

      Fetch a single module script given url, settings - object, "script", options, settings object, - "client", moduleRequest, false, and with the following steps - given result:

      - -
        -
      1. If result is null, run onComplete with null, and abort these - steps.

      2. - -
      3. Let visited set be « (url, moduleType) ».

      4. - -
      5. Fetch the descendants - of and link result given settings object, destination, - visited set, and onComplete.

      6. + data-x="">script", and onComplete.

    @@ -96217,18 +96169,11 @@ document.querySelector("button").addEventListener("click", bound);
  • Run onComplete given result.

  • -

    If result is not null, optionally perform the following steps:

    +

    If result is not null, optionally fetch the descendants of and link result given + settings object, destination, and an empty algorithm.

    -
      -
    1. Let visited set be « (url, "javascript") - ».

    2. - -
    3. Fetch the - descendants of and link result given settings object, - destination, visited set, and with an empty algorithm.

    4. -
    - -

    Generally, performing these steps will be beneficial for performance, as it +

    Generally, performing this step will be beneficial for performance, as it allows pre-loading the modules that will invariably be requested later, via algorithms such as fetch an external module script graph that fetch the entire graph. However, user agents might wish to skip them in bandwidth-constrained situations, or situations where the @@ -96252,12 +96197,9 @@ document.querySelector("button").addEventListener("click", bound);

  • If script is null, run onComplete given null, and return.

  • -
  • Let visited set be an empty set.

  • - -
  • Fetch the - descendants of and link script, given settings object, the - destination "script", visited set, and - onComplete.

  • +
  • Fetch the descendants of + and link script, given settings object, the destination "script", and onComplete.

  • To fetch a module worker script graph @@ -96327,7 +96269,7 @@ document.querySelector("button").addEventListener("click", bound);

    This diagram illustrates how these algorithms relate to the ones above, as well as to each other:

    - + fetch the descendants of and link a module script - - - - - - fetch the descendants of a module script - - - - - - - - internal module script graph fetching procedure - - -

    To fetch a worklet/module worker script graph given a url, a fetch @@ -96465,211 +96382,86 @@ document.querySelector("button").addEventListener("click", bound);

  • If result is null, run onComplete given null, and abort these steps.

  • -
  • Let visited set be « (url, "javascript") - ».

  • - -
  • Fetch the - descendants of and link result given fetch client settings - object, destination, visited set, and - onComplete. If performFetch was given, pass it along as well.

  • +
  • Fetch the descendants + of and link result given fetch client settings object, + destination, and onComplete. If performFetch was given, pass + it along as well.

  • To fetch the descendants of and link a module script module - script, given a fetch client settings object, a destination, a - visited set, an onComplete algorithm, and an optional perform the fetch hook performFetch, run - these steps. onComplete must be an algorithm accepting null (on failure) or a - module script (on success).

    - -
      -
    1. -

      Fetch the descendants of - module script, given fetch client settings object, destination, - visited set, and onFetchDescendantsComplete as defined below. If - performFetch was given, pass it along as well.

      - -

      onFetchDescendantsComplete given result is the following algorithm:

      - -
        -
      1. -

        If result is null, then run onComplete given result, and - abort these steps.

        - -

        In this case, there was an error fetching one or more of the descendants. We - will not attempt to link.

        -
      2. - -
      3. Let parse error be the result of finding the first parse error - given result.

      4. - -
      5. -

        If parse error is null, then:

        - -
          -
        1. Let record be result's record.

        2. - -
        3. -

          Perform record.Link().

          - -

          This step will recursively call Link on all of - the module's unlinked dependencies.

          - -

          If this throws an exception, set result's error to rethrow to that exception.

          -
        4. -
        -
      6. - -
      7. Otherwise, set result's error - to rethrow to parse error.

      8. - -
      9. Run onComplete given result.

      10. -
      -
    2. -
    - -

    To fetch the descendants of a module script module script, given a - fetch client settings object, a destination, a visited set, an + script, given a fetch client settings object, a destination, an onComplete algorithm, and an optional perform the fetch hook performFetch, run these steps. onComplete must be an algorithm accepting null (on failure) or a module script (on success).

      -
    1. If module script's record is null, - run onComplete with module script and return.

    2. -
    3. Let record be module script's record.

    4. -
    5. If record is not a Cyclic Module Record, or if - record.[[RequestedModules]] is empty, run - onComplete with module script and return.

    6. - -
    7. Let moduleRequests be a new empty list.

    8. -
    9. -

      For each ModuleRequest Record - requested of record.[[RequestedModules]],

      +

      If record is null, then:

        -
      1. Let url be the result of resolving - a module specifier given module script and - requested.[[Specifier]].

      2. - -
      3. Assert: the previous step never throws an exception, because resolving a module specifier must have been previously successful with these same two - arguments.

      4. - -
      5. Let moduleType be the result of running the module type from module - request steps given requested.

      6. - -
      7. -

        If visited set does not contain - (url, moduleType), then:

        +
      8. Set module script's error to + rethrow to module script's parse error.

      9. -
          -
        1. Append requested to - moduleRequests.

        2. +
        3. Run onComplete given module script.

        4. -
        5. Append (url, moduleType) to - visited set.

        6. -
        - +
      10. Return.

    10. -
    11. Let options be the descendant script fetch options for module - script's fetch options.

    12. - -
    13. Assert: options is not null, as module script is a - JavaScript module script.

    14. +
    15. Let state be Record { [[ParseError]]: null, [[Destination]]: + destination, [[PerformFetch]]: null }.

    16. -
    17. Let pendingCount be the length of moduleRequests.

    18. +
    19. If performFetch was given, set state.[[PerformFetch]] to + performFetch.

    20. -
    21. If pendingCount is zero, run onComplete with module - script.

    22. +
    23. +

      Let loading promise be record.LoadRequestedModules(state).

      -
    24. Let failed be false.

    25. +

      This step will recursively load all the module transitive dependencies.

      +
    26. -

      For each moduleRequest in - moduleRequests, perform the internal module script graph fetching - procedure given moduleRequest, fetch client settings object, - destination, options, module script, visited set, - and onInternalFetchingComplete as defined below. If performFetch was - given, pass it along as well.

      - -

      onInternalFetchingComplete given result is the following algorithm:

      +

      Upon fulfillment of loading promise, run the following steps:

        -
      1. If failed is true, then abort these steps.

      2. - -
      3. If result is null, then set failed to true, run - onComplete with null, and abort these steps.

      4. +
      5. +

        Perform record.Link().

        -
      6. Assert: pendingCount is greater than zero.

      7. +

        This step will recursively call Link on all of + the module's unlinked dependencies.

        -
      8. Decrement pendingCount by one.

      9. +

        If this throws an exception, catch it, and set module script's error to rethrow to that exception.

        + -
      10. If pendingCount is zero, run onComplete with module - script.

      11. +
      12. Run onComplete given module script.

      - -

      The fetches performed by the internal module script graph fetching - procedure are performed in parallel to each other.

    27. -
    - -

    To perform the internal module script graph fetching procedure given a - moduleRequest, a fetch client settings object, a destination, - some options, a referringScript, a visited set, an - onComplete algorithm, and an optional perform the fetch hook performFetch, run - these steps. onComplete must be an algorithm accepting null (on failure) or a - module script (on success).

    - -
      -
    1. Let url be the result of resolving - a module specifier given referringScript and - moduleRequest.[[Specifier]].

    2. - -
    3. Assert: the previous step never throws an exception, because resolving a module specifier must have been previously successful with these same two - arguments.

    4. - -
    5. Let moduleType be the result of running the module type from module - request steps given moduleRequest.

    6. - -
    7. Assert: visited set contains - (url, moduleType).

    8. -

      Fetch a single module script given url, fetch client settings - object, destination, options, referringScript's - settings object, referringScript's base URL, moduleRequest, false, and - onSingleFetchComplete as defined below. If performFetch was given, pass - it along as well.

      - -

      onSingleFetchComplete given result is the following algorithm:

      +

      Upon rejection of loading promise, run the + following steps:

        -
      1. If result is null, run onComplete with null, and abort these - steps.

      2. +
      3. If state.[[ParseError]] is not null, set module script's error to rethrow to + state.[[ParseError]] and run onComplete given module + script.

      4. -
      5. Fetch the descendants of - result given fetch client settings object, destination, - visited set, and with onComplete. If performFetch was given, - pass it along as well.

      6. -
      +
    9. +

      Otherwise, run onComplete given null.

      -

      +

      state.[[ParseError]] is null when loading promise is + rejected due to a loading error.

      +
    10. +
    @@ -96688,12 +96480,11 @@ document.querySelector("button").addEventListener("click", bound); running the module type from module request steps given moduleRequest.

    -
  • Assert: the result of running the module type allowed steps - given moduleType and module map settings object is true. Otherwise we would - not have reached this point because a failure would have been raised when inspecting - moduleRequest.[[Assertions]] in create a JavaScript module script or - fetch an import() module script graph.

  • +
  • Assert: the result of running the module type allowed steps given + moduleType and module map settings object is true. Otherwise we would not + have reached this point because a failure would have been raised when inspecting + moduleRequest.[[Assertions]] in create + a JavaScript module script or fetch a single imported module script.

  • Let moduleMap be module map settings object's module map.

  • @@ -96805,61 +96596,30 @@ document.querySelector("button").addEventListener("click", bound); -

    To find the first parse error given a root - moduleScript and an optional discoveredSet:

    +

    To fetch a single imported module script, given a url, a settings + object, a destination, some options, a referrer, a + moduleRequest, an onComplete algorithm, and an optional perform the fetch hook performFetch, run + these steps. onComplete must be an algorithm accepting null (on failure) or a + module script (on success).

      -
    1. Let moduleMap be moduleScript's settings object's - module map.

    2. - -
    3. If discoveredSet was not given, let it be an empty set.

    4. - -
    5. Append moduleScript to - discoveredSet.

    6. - -
    7. If moduleScript's record is null, - then return moduleScript's parse - error.

    8. - -
    9. If moduleScript's record is not a - Cyclic Module Record, then return null.

    10. - -
    11. Let moduleRequests be the value of moduleScript's record's [[RequestedModules]] internal slot.

    12. - -
    13. -

      For each moduleRequest of - moduleRequests:

      - -
        -
      1. Let childURL be the result of resolving a module specifier given moduleScript and - moduleRequest.[[Specifier]]. (This will never throw an exception, as otherwise - moduleScript would have been marked - as itself having a parse error.)

      2. - -
      3. Let moduleType be the result of running the module type from module - request steps given moduleRequest.

      4. - -
      5. Let childModule be moduleMap[(childURL, - moduleType)].

      6. - -
      7. Assert: childModule is a module script (i.e., it is - not "fetching" or null); by now all module - scripts in the graph rooted at moduleScript will have successfully been - fetched.

      8. - -
      9. If discoveredSet already contains - childModule, continue.

      10. +
      11. Assert: moduleRequest.[[Assertions]] does not contain any Record + entry such that entry.[[Key]] is not "type", because + we only asked for "type" assertions in + HostGetSupportedImportAssertions.

      12. -
      13. Let childParseError be the result of finding the first parse - error given childModule and discoveredSet.

      14. +
      15. Let moduleType be the result of running the module type from module + request steps given moduleRequest.

      16. -
      17. If childParseError is not null, return childParseError.

      18. -
      -
    14. +
    15. If the result of running the module type allowed steps given + moduleType and settings object is false, then run onComplete + given null, and return.

    16. -
    17. Return null.

    18. +
    19. Fetch a single module script given url, settings + object, destination, options, settings object, + referrer, moduleRequest, false, and onComplete. If + performFetch was given, pass it along as well.

    Creating scripts
    @@ -97046,7 +96806,7 @@ document.querySelector("button").addEventListener("click", bound);

    Run the steps to synchronously replace the rules of a CSSStyleSheet on sheet given source.

    -

    If this throws an exception, set script's If this throws an exception, catch it, and set script's parse error to that exception, and return script.

    @@ -97081,7 +96841,7 @@ document.querySelector("button").addEventListener("click", bound);
  • Let result be ParseJSONModule(source).

    -

    If this throws an exception, set script's If this throws an exception, catch it, and set script's parse error to that exception, and return script.

  • @@ -98751,9 +98511,8 @@ dictionary PromiseRejectionEventInit : EventInitAs a consequence, this means that when the import() expression is evaluated, there will still be no active script. Fortunately that is handled by our - implementations of HostResolveImportedModule and - HostImportModuleDynamically, by falling back to using the current settings - object's API base URL.

    + implementation of HostLoadImportedModule by falling back to using the + current settings object's API base URL.

    @@ -98789,8 +98548,8 @@ dictionary PromiseRejectionEventInit : EventInit.

    The returned promise will be rejected if an invalid specifier is given, or if a failure is - encountered while fetching or evaluating the resulting module graph.

    + encountered while fetching or evaluating the + resulting module graph.

    This syntax can be used inside both classic and module scripts. It thus provides a bridge into the module-script @@ -98874,8 +98633,8 @@ import "https://example.com/foo/../module2.mjs";

    This can result in two separate fetches and two separate module evaluations being performed. This is a willful violation of a constraint recommended (but not required) by the - import assertions specification stating that each call to HostResolveImportedModule - with the same (referencingScriptOrModule, moduleRequest.[[Specifier]]) pair + import assertions specification stating that each call to HostLoadImportedModule + with the same (referrer, moduleRequest.[[Specifier]]) pair must return the same Module Record.

    @@ -98947,158 +98706,162 @@ import "https://example.com/foo/../module2.mjs";
  • Let resolveFunction be ! CreateBuiltinFunction(steps, 1, "resolve", « »).

  • -
  • Return « Record { [[Key]]: "url", - [[Value]]: urlString }, Record { [[Key]]: "

    Return « Record { [[Key]]: "url", + [[Value]]: urlString }, Record { [[Key]]: "resolve", [[Value]]: resolveFunction } ».

  • -
    HostImportModuleDynamically(referencingScriptOrModule, - moduleRequest, promiseCapability)
    +
    HostLoadImportedModule(referrer, + moduleRequest, loadState, payload)

    JavaScript contains an implementation-defined HostImportModuleDynamically abstract operation. - User agents must use the following implementation:

    + data-x="js-HostLoadImportedModule">HostLoadImportedModule
    abstract operation. User agents + must use the following implementation:

    + +

    This specification expects the second parameter to be a ModuleRequest + Record, instead of a string as specified by ECMA-262. This is under the assumption that the + import assertions proposal, when updated to use HostLoadImportedModule + instead of the previous module loading hooks, will update the abstract operation passing a + ModuleRequest Record.

    1. Let settings object be the current settings object.

    2. If settings object's global - object implements WorkletGlobalScope or - ServiceWorkerGlobalScope, then:

      + object implements WorkletGlobalScope or ServiceWorkerGlobalScope + and loadState is undefined, then:

      + +

      loadState is undefined when the current fetching process has been + initiated by a dynamic import() call.

        -
      1. Let completion be Completion { [[Type]]: throw, [[Value]]: a new +

      2. Let completion be the Completion Record { [[Type]]: throw, [[Value]]: a new TypeError, [[Target]]: empty }.

      3. -
      4. Perform FinishDynamicImport(referencingScriptOrModule, - moduleRequest, promiseCapability, completion).

      5. +
      6. Perform FinishLoadingImportedModule(referrer, + moduleRequest, payload, completion).

      7. Return.

    3. -
    4. Let referencing script be null.

    5. +
    6. Let referencingScript be null.

    7. Let fetch options be the default classic script fetch options.

    8. +
    9. Let fetch referrer be "client".

    10. +
    11. -

      If referencingScriptOrModule is not null, then:

      +

      If referrer is a Script Record or a Module Record, then:

        -
      1. Set referencing script to - referencingScriptOrModule.[[HostDefined]].

        +
      2. Set referencingScript to referrer.[[HostDefined]].

        -
      3. Set settings object to referencing script's settings +

      4. Set settings object to referencingScript's settings object.

      5. Set fetch options to the descendant script fetch options for - referencing script's fetch + referencingScript's fetch options.

      6. -
      7. Assert: fetch options is not null, as referencing - script is a classic script or a JavaScript module +

      8. Assert: fetch options is not null, as + referencingScript is a classic script or a JavaScript module script.

      9. -
      - -

      As explained for HostResolveImportedModule, in the common - case, referencingScriptOrModule is non-null.

      -
    12. -
    13. -

      Fetch an import() module script graph given moduleRequest, - referencing script, settings object, fetch options, and with - the following steps given result:

      +
    14. +

      If loadState is not undefined, set fetch referrer to + referrer's base URL.

      -
        -
      1. Let promise be null. +

        We check loadState to not propagate the referrer when using dynamic + imports. Issue #3744 looks into + aligning dynamic imports with static imports.

        +
      2. +
      -
    15. If result is null, then set promise to a promise rejected - with a new TypeError.

    16. +
      +

      referrer is usually a Script Record or a Module Record, but it will not be so for event handlers per the get the current value of the event + handler algorithm. For example, given:

      -
    17. Otherwise, set promise to the result of running a module script given result and true.

    18. +
      <button onclick="import('./foo.mjs')">Click me</button>
      -
    19. Perform FinishDynamicImport(referencingScriptOrModule, - moduleRequest, promiseCapability, promise).

    20. -
    +

    If a click event occurs, then at the time the + import() expression runs, GetActiveScriptOrModule will return null, + and this operation will receive the current realm as a fallback + referrer.

    + - - -
    HostResolveImportedModule(referencingScriptOrModule, - moduleRequest)
    -

    JavaScript contains an implementation-defined HostResolveImportedModule abstract operation. User - agents must use the following implementation:

    +
  • Disallow further import maps given settings object.

  • -
      -
    1. Let moduleMap and referencingScript be null.

    2. +
    3. Let url be the result of resolving a + module specifier given referencingScript and + moduleRequest.[[Specifier]], catching any exceptions. If they throw an exception, let + resolutionError be the thrown exception.

    4. -

      If referencingScriptOrModule is not null, then:

      +

      If the previous step threw an exception, then:

        -
      1. Set referencingScript to - referencingScriptOrModule.[[HostDefined]].

      2. +
      3. Let completion be the Completion Record { [[Type]]: throw, + [[Value]]: resolutionError, [[Target]]: empty }.

      4. + +
      5. Perform FinishLoadingImportedModule(referrer, + moduleRequest, payload, completion).

      6. -
      7. Set moduleMap to referencingScript's settings - object's module map.

      8. +
      9. Return.

    5. -
    6. -

      Otherwise:

      - -
        -
      1. Assert: there is a current settings object.

      2. - -
      3. Set moduleMap to the current settings object's module map.

      4. -
      +
    7. Let destination be "script".

    8. -
      -

      referencingScriptOrModule is not usually null, but will be so for event handlers - per the get the current value of - the event handler algorithm. For example, given:

      +
    9. If loadState is not undefined, then set destination to + loadState.[[Destination]].

    10. -
      <button onclick="import('./foo.mjs')">Click me</button>
      +
    11. +

      Fetch a single imported module script given url, settings + object, destination, fetch options, fetch referrer, + moduleRequest, and onSingleFetchComplete as defined below. If + loadState is not undefined and loadState.[[PerformFetch]] is not null, + pass loadState.[[PerformFetch]] along as well.

      -

      If a click event occurs, then at the time the - import() expression runs, GetActiveScriptOrModule will return null, - which will be passed to this abstract operation when HostResolveImportedModule is called by - FinishDynamicImport.

      -
    12. - +

      onSingleFetchComplete given moduleScript is the following + algorithm:

      -
    13. Let url be the result of resolving a - module specifier given referencingScript and - moduleRequest.[[Specifier]].

    14. +
        +
      1. If moduleScript is null, then let completion be the + Completion Record { [[Type]]: throw, [[Value]]: a new TypeError, + [[Target]]: empty }.

      2. -
      3. Assert: the previous step never throws an exception, because resolving a module specifier must have been - previously successful with these same two arguments (either while creating the corresponding module script, - or in fetch an import() module script graph).

      4. +
      5. +

        Otherwise, if moduleScript's parse + error is not null, then:

        -
      6. Let moduleType be the result of running the module type from module - request steps given moduleRequest.

      7. +
          +
        1. Let parseError be moduleScript's parse error.

        2. -
        3. Let resolvedModuleScript be moduleMap[(url, - moduleType)]. (This entry must exist for us to have - gotten to this point.)

        4. +
        5. Let completion be the Completion Record { [[Type]]: throw, + [[Value]]: parseError, [[Target]]: empty }.

        6. -
        7. Assert: resolvedModuleScript is a module script - (i.e., is not null or "fetching").

        8. +
        9. If loadState is not undefined and loadState.[[ParseError]] is + null, set loadState.[[ParseError]] to parseError.

        10. +
        + -
      8. Assert: resolvedModuleScript's record is not null.

        +
      9. Otherwise, let completion be the Completion Record { [[Type]]: + normal, [[Value]]: result's record, + [[Target]]: empty }.

      10. -
      11. Return resolvedModuleScript's record.

      12. +
      13. Perform FinishLoadingImportedModule(referrer, + moduleRequest, payload, completion).

      14. +
      +
    HostGetSupportedImportAssertions()
    @@ -101077,9 +100840,8 @@ typedef OnBeforeUnloadEventHandlerNonNull? OnBeforeUnl

    In practice, this only affects the resolution of relative URLs via import(), which consult the base URL of the associated - script. Nulling out [[ScriptOrModule]] means that HostResolveImportedModule and - HostImportModuleDynamically will fall back to the current settings - object's API base URL.

    + script. Nulling out [[ScriptOrModule]] means that HostLoadImportedModule will + fall back to the current settings object's API base URL.

    From fe39edb2694a25384819c062c6725f99167ab737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Wed, 5 Oct 2022 18:55:52 +0200 Subject: [PATCH 3/6] Fix fetch referrer of static imports triggered by dynamic imports --- source | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/source b/source index 0e2463416b3..4b38f2d4398 100644 --- a/source +++ b/source @@ -98734,7 +98734,8 @@ import "https://example.com/foo/../module2.mjs";
    and loadState is undefined, then:

    loadState is undefined when the current fetching process has been - initiated by a dynamic import() call.

    + initiated by a dynamic import() call, either directly or when loading the + transitive dependencies of the dynamically imported module.

    1. Let completion be the Completion Record { [[Type]]: throw, [[Value]]: a new @@ -98773,12 +98774,21 @@ import "https://example.com/foo/../module2.mjs"; script.

    2. -

      If loadState is not undefined, set fetch referrer to - referrer's base URL.

      +

      If none of the following conditions is true

      -

      We check loadState to not propagate the referrer when using dynamic - imports. Issue #3744 looks into - aligning dynamic imports with static imports.

      +
        +
      • referrer is a Script Record
      • + +
      • referrer is a Module Record and + referrer.[[Status]] is one of evaluating, evaluating-async or evaluated
      • +
      + +

      then set fetch referrer to referrer's base URL.

      + +

      We set fetch referrer conditionally to not propagate the referrer + when using import(). Issue + #3744 looks into aligning dynamic imports with static imports.

    From 40eab38d8315facd58ae5d1fae7685c10035cb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Fri, 7 Oct 2022 10:36:52 +0200 Subject: [PATCH 4/6] domenic review --- source | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/source b/source index 4b38f2d4398..4b8c1df1aae 100644 --- a/source +++ b/source @@ -96198,7 +96198,7 @@ document.querySelector("button").addEventListener("click", bound);
  • If script is null, run onComplete given null, and return.

  • Fetch the descendants of - and link script, given settings object, the destination " script, given settings object, "script", and onComplete.

  • @@ -96269,7 +96269,7 @@ document.querySelector("button").addEventListener("click", bound);

    This diagram illustrates how these algorithms relate to the ones above, as well as to each other:

    - +
    script
    .

  • -

    If none of the following conditions is true

    +

    If neither of the following conditions are true:

      -
    • referrer is a Script Record
    • +
    • referrer is a Script Record; or
    • referrer is a Module Record and - referrer.[[Status]] is one of evaluating, evaluating-async or evaluated
    • + referrer.[[Status]] is one of evaluating, evaluating-async or evaluated,

    then set fetch referrer to referrer's

    If the previous step threw an exception, then:

      -
    1. Let completion be the Completion Record { [[Type]]: throw, +

    2. Let completion be Completion Record { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }.

    3. Perform FinishLoadingImportedModule(referrer, @@ -98844,9 +98844,11 @@ import "https://example.com/foo/../module2.mjs"; algorithm:

        -
      1. If moduleScript is null, then let completion be the - Completion Record { [[Type]]: throw, [[Value]]: a new TypeError, - [[Target]]: empty }.

      2. +
      3. Let completion be null.

      4. + +
      5. If moduleScript is null, then set completion to Completion + Record { [[Type]]: throw, [[Value]]: a new TypeError, [[Target]]: empty + }.

      6. Otherwise, if moduleScript's parse @@ -98856,7 +98858,7 @@ import "https://example.com/foo/../module2.mjs";

      7. Let parseError be moduleScript's parse error.

      8. -
      9. Let completion be the Completion Record { [[Type]]: throw, +

      10. Set completion to Completion Record { [[Type]]: throw, [[Value]]: parseError, [[Target]]: empty }.

      11. If loadState is not undefined and loadState.[[ParseError]] is @@ -98864,7 +98866,7 @@ import "https://example.com/foo/../module2.mjs";

    4. -
    5. Otherwise, let completion be the Completion Record { [[Type]]: +

    6. Otherwise, set completion to Completion Record { [[Type]]: normal, [[Value]]: result's record, [[Target]]: empty }.

    7. From 90672d3aa26e57f5aae7f332a5888f588538ec35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 19 Dec 2022 12:49:42 +0100 Subject: [PATCH 5/6] Update links to ECMA-262 --- source | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source b/source index 4b8c1df1aae..6002c1da11a 100644 --- a/source +++ b/source @@ -2889,7 +2889,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
    8. The Source Text Module Record specification type and its Evaluate, Link and - LoadRequestedModules methods
    9. + LoadRequestedModules methods
    10. The ArrayCreate abstract operation
    11. The Call abstract operation
    12. @@ -2903,7 +2903,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
    13. The DetachArrayBuffer abstract operation
    14. The EnumerableOwnProperties abstract operation
    15. The FinishDynamicImport abstract operation
    16. -
    17. The FinishLoadingImportedModule abstract operation
    18. +
    19. The FinishLoadingImportedModule abstract operation
    20. The OrdinaryFunctionCreate abstract operation
    21. The Get abstract operation
    22. The GetActiveScriptOrModule abstract operation
    23. @@ -2914,7 +2914,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
    24. The HostEnqueuePromiseJob abstract operation
    25. The HostEnsureCanAddPrivateElement abstract operation
    26. The HostEnsureCanCompileStrings abstract operation
    27. -
    28. The HostLoadImportedModule abstract operation
    29. +
    30. The HostLoadImportedModule abstract operation
    31. The HostMakeJobCallback abstract operation
    32. The HostPromiseRejectionTracker abstract operation
    33. The InitializeHostDefinedRealm abstract operation
    34. From 75e7bf018565b822ac86867a5938cd99ca479cc5 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Mon, 26 Dec 2022 18:52:49 +0900 Subject: [PATCH 6/6] Minor fixes --- source | 83 ++++++++++++++++++++---------------------------------- styles.css | 26 +++++++++++++++++ 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/source b/source index 6002c1da11a..d569fba1fa5 100644 --- a/source +++ b/source @@ -95857,7 +95857,7 @@ document.querySelector("button").addEventListener("click", bound); sequence containing the response body. isTopLevel will be true for all classic script fetches, and for the initial fetch when fetching an external module script graph, or fetching an external module script graph or fetching a module worker script graph, but false for the fetches resulting from import statements encountered throughout the graph or from import() expressions.

      @@ -96269,28 +96269,7 @@ document.querySelector("button").addEventListener("click", bound);

      This diagram illustrates how these algorithms relate to the ones above, as well as to each other:

      - - - + @@ -96421,14 +96400,14 @@ document.querySelector("button").addEventListener("click", bound); performFetch.

    35. -

      Let loading promise be record.Let loadingPromise be record.LoadRequestedModules(state).

      This step will recursively load all the module transitive dependencies.

    36. -

      Upon fulfillment of loading promise, run the following steps:

      +

      Upon fulfillment of loadingPromise, run the following steps:

      1. @@ -96446,7 +96425,7 @@ document.querySelector("button").addEventListener("click", bound);
      2. -

        Upon rejection of loading promise, run the +

        Upon rejection of loadingPromise, run the following steps:

          @@ -96458,7 +96437,7 @@ document.querySelector("button").addEventListener("click", bound);
        1. Otherwise, run onComplete given null.

          -

          state.[[ParseError]] is null when loading promise is +

          state.[[ParseError]] is null when loadingPromise is rejected due to a loading error.

        @@ -98712,7 +98691,18 @@ import "https://example.com/foo/../module2.mjs"; ».

      -
      HostLoadImportedModule(referrer, +
      HostGetSupportedImportAssertions()
      + +

      The Import Assertions proposal contains an implementation-defined + HostGetSupportedImportAssertions + abstract operation. User agents must use the following implementation:

      + +
        +
      1. Return « "type" ».

      2. +
      + +
      HostLoadImportedModule(referrer, moduleRequest, loadState, payload)

      JavaScript contains an implementation-defined ModuleRequest Record.

        -
      1. Let settings object be the current settings object.

      2. +
      3. Let settingsObject be the current settings object.

      4. -

        If settings object's global +

        If settingsObject's global object implements WorkletGlobalScope or ServiceWorkerGlobalScope and loadState is undefined, then:

        @@ -98738,8 +98728,8 @@ import "https://example.com/foo/../module2.mjs"; transitive dependencies of the dynamically imported module.

          -
        1. Let completion be the Completion Record { [[Type]]: throw, [[Value]]: a new - TypeError, [[Target]]: empty }.

        2. +
        3. Let completion be Completion Record { [[Type]]: throw, + [[Value]]: a new TypeError, [[Target]]: empty }.

        4. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).

        5. @@ -98750,10 +98740,10 @@ import "https://example.com/foo/../module2.mjs";
        6. Let referencingScript be null.

        7. -
        8. Let fetch options be the default classic script fetch +

        9. Let fetchOptions be the default classic script fetch options.

        10. -
        11. Let fetch referrer be "client".

        12. +
        13. Let fetchReferrer be "client".

        14. If referrer is a Script Record or a

          1. Set referencingScript to referrer.[[HostDefined]].

            -
          2. Set settings object to referencingScript's settings +

          3. Set settingsObject to referencingScript's settings object.

          4. -
          5. Set fetch options to the descendant script fetch options for +

          6. Set fetchOptions to the descendant script fetch options for referencingScript's fetch options.

          7. -
          8. Assert: fetch options is not null, as +

          9. Assert: fetchOptions is not null, as referencingScript is a classic script or a JavaScript module script.

          10. @@ -98783,10 +98773,10 @@ import "https://example.com/foo/../module2.mjs"; referrer.[[Status]] is one of evaluating, evaluating-async or evaluated, -

            then set fetch referrer to referrer's then set fetchReferrer to referrer's base URL.

            -

            We set fetch referrer conditionally to not propagate the referrer +

            We set fetchReferrer conditionally to not propagate the referrer when using import(). Issue #3744 looks into aligning dynamic imports with static imports.

            @@ -98807,7 +98797,7 @@ import "https://example.com/foo/../module2.mjs"; -
          11. Disallow further import maps given settings object.

          12. +
          13. Disallow further import maps given settingsObject.

          14. Let url be the result of resolving a module specifier given referencingScript and @@ -98835,7 +98825,7 @@ import "https://example.com/foo/../module2.mjs";

          15. Fetch a single imported module script given url, settings - object, destination, fetch options, fetch referrer, + object, destination, fetchOptions, fetchReferrer, moduleRequest, and onSingleFetchComplete as defined below. If loadState is not undefined and loadState.[[PerformFetch]] is not null, pass loadState.[[PerformFetch]] along as well.

            @@ -98876,17 +98866,6 @@ import "https://example.com/foo/../module2.mjs";
          -
          HostGetSupportedImportAssertions()
          - -

          The Import Assertions proposal contains an implementation-defined - HostGetSupportedImportAssertions - abstract operation. User agents must use the following implementation:

          - -
            -
          1. Return « "type" ».

          2. -
          -

          Event loops

          diff --git a/styles.css b/styles.css index 5ad4abcc5c3..706560cec4f 100644 --- a/styles.css +++ b/styles.css @@ -111,6 +111,32 @@ td.eg { border-width: thin; text-align: center; } #abstractimg .horizontal, #abstractimg .left { word-spacing: 12px; font-size: 18px; text-anchor: middle; } #abstractimg .right { font-size: 25px; } +#module-script-fetching-diagram { + display: block; + margin: 0 auto; + width: 100%; + max-width: 1024px; +} + +#module-script-fetching-diagram rect { + stroke: black; + fill: transparent; +} + +#module-script-fetching-diagram path { + stroke: black; +} +#module-script-fetching-diagram path[marker-end] { + fill: transparent; +} + +#module-script-fetching-diagram a { + text-align: center; + display: flex; + align-items: center; + justify-content: center; +} + .jake-diagram { border-style: hidden none hidden hidden; table-layout: fixed;