Skip to content

Commit 101fe60

Browse files
domenicAlice Boxhall
authored and
Alice Boxhall
committed
Fix error cases of <script type=module>
There are several different ways things can go wrong with <script type=module>. In order from earliest to latest, for a single module script, they are: - Fetching failures - Parsing failures - Invalid module specifiers - Instantiation failures - Evaluation failures This tweaks the way that these errors interact, to ensure that fetching failures are treated one way, causing the <script>'s "error" event to fire, and the other failures are uniformly treated as errors running the script, causing the global's "error" event to fire. This also makes it clear that when fetching descendant module scripts, you can bail out early if one of them fails to fetch or has previously been discovered to be errored. Evaluation failures are particularly tricky for dependencies, as usually ModuleEvaluation() is a no-op if it has happened previously (either successfully or not). This is discussed in more depth in tc39/ecma262#862. To work around this, we need to store the evaluation error, if one occurs, similar to what we already do for instantiation errors. Fixes whatwg#2567. However, there are still problems with this setup, which may need further infrastructure changes; see: - whatwg#2595 (comment) - whatwg#2629 - whatwg#2630 But for now the improvement given by this commit is enough to merge it.
1 parent 4330abb commit 101fe60

File tree

1 file changed

+121
-80
lines changed

1 file changed

+121
-80
lines changed

Diff for: source

+121-80
Original file line numberDiff line numberDiff line change
@@ -86557,24 +86557,24 @@ interface <dfn>NavigatorOnLine</dfn> {
8655786557

8655886558
</dd>
8655986559

86560-
<dt>An <dfn data-x="concept-module-script-instantiation-state">instantiation state</dfn></dt>
86560+
<dt>A <dfn data-x="concept-module-script-state">state</dfn></dt>
8656186561

8656286562
<dd>
8656386563

8656486564
<p>One of "<code data-x="">uninstantiated</code>", "<code data-x="">errored</code>", or "<code
8656586565
data-x="">instantiated</code>", used to prevent reinvocation of <span
8656686566
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span> on modules that
86567-
failed to instantiate previously.</p>
86567+
failed to instantiate previously, and to ensure errors during parsing, instantiation, or
86568+
evaluation are remembered and propagated correctly.</p>
8656886569

8656986570
</dd>
8657086571

86571-
<dt>An <dfn data-x="concept-module-script-instantiation-error">instantiation error</dfn></dt>
86572+
<dt>An <dfn data-x="concept-module-script-error">error</dfn></dt>
8657286573

8657386574
<dd>
8657486575

8657586576
<p>A JavaScript value, which has meaning only if the <span
86576-
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
86577-
data-x="">errored</code>".</p>
86577+
data-x="concept-module-script-state">state</span> is "<code data-x="">errored</code>".</p>
8657886578

8657986579
</dd>
8658086580

@@ -86607,6 +86607,33 @@ interface <dfn>NavigatorOnLine</dfn> {
8660786607

8660886608
</dl>
8660986609

86610+
<p>To <dfn>error a module script</dfn> <var>script</var> with a given value <var>error</var>,
86611+
perform the following steps:</p>
86612+
86613+
<ol>
86614+
<li><p>Assert: <var>script</var>'s <span data-x="concept-module-script-state">state</span> is not
86615+
"<code data-x="">errored</code>".</p></li>
86616+
86617+
<li>
86618+
<p>If <var>script</var>'s <span data-x="concept-module-script-module-record">module
86619+
record</span> is set, then:</p>
86620+
86621+
<ol>
86622+
<li><p>Set <var>script</var> <span data-x="concept-module-script-module-record">module
86623+
record</span>'s [[HostDefined]] field to undefined.</p></li>
86624+
86625+
<li><p>Set <var>script</var>'s <span data-x="concept-module-script-module-record">module
86626+
record</span> to null.</p></li>
86627+
</ol>
86628+
</li>
86629+
86630+
<li><p>Set <var>script</var>'s <span data-x="concept-module-script-state">state</span> to
86631+
"<code data-x="">errored</code>".</p></li>
86632+
86633+
<li><p>Set <var>script</var>'s <span data-x="concept-module-script-error">error</span> to
86634+
<var>error</var>.</p></li>
86635+
</ol>
86636+
8661086637
<hr>
8661186638

8661286639
<p>An <dfn data-export="">environment</dfn> is an object that identifies the settings of a
@@ -87041,73 +87068,49 @@ interface <dfn>NavigatorOnLine</dfn> {
8704187068
<li><p>If <var>result</var> is null, asynchronously complete this algorithm with null and abort
8704287069
these steps.</p></li>
8704387070

87071+
<li><p>If <var>result</var>'s <span data-x="concept-module-script-state">state</span> is "<code
87072+
data-x="">instantiated</code>" or "<code data-x="">errored</code>", asynchronously complete this
87073+
algorithm with <var>result</var>, and abort these steps.</p></li>
87074+
87075+
<li><p>Assert: <var>result</var>'s <span data-x="concept-module-script-state">state</span> is
87076+
"<code data-x="">uninstantiated</code>".</p></li>
87077+
8704487078
<li>
87045-
<p>Otherwise, <var>result</var> is a <span>module script</span>. <span data-x="fetch the
87046-
descendants of a module script">Fetch the descendants</span> of <var>result</var> given
87047-
<var>destination</var> and an ancestor list obtained by appending <var>url</var> to <var>ancestor
87048-
list</var>. Wait for <span data-x="fetch the descendants of a module script">fetching the
87049-
descendants of a module script</span> to asynchronously complete with <var>descendants
87050-
result</var> before proceeding to the next step.</p>
87079+
<p><span data-x="fetch the descendants of a module script">Fetch the
87080+
descendants</span> of <var>result</var> given <var>destination</var> and an ancestor list
87081+
obtained by appending <var>url</var> to <var>ancestor list</var>. Wait for <span data-x="fetch
87082+
the descendants of a module script">fetching the descendants of a module script</span> to
87083+
asynchronously complete with <var>descendants result</var> before proceeding to the next step.</p>
8705187084

8705287085
<p class="note">If the asynchronous completion result is null, meaning that fetching one of the
8705387086
descendants failed, we still proceed through the next set of steps. A failure will shortly occur
8705487087
during instantiation, which we then react to appropriately. The error signal is eventually
8705587088
propagated to the caller of this algorithm in the last step.</p>
8705687089
</li>
8705787090

87058-
<li><p>Let <var>instantiationStatus</var> be null.</p></li>
87059-
87060-
<li><p>If <var>result</var>'s <span data-x="concept-module-script-instantiation-state">instantiation
87061-
state</span> is "<code data-x="">errored</code>", then set <var>instantiationStatus</var> to
87062-
Completion { [[Type]]: throw, [[Value]]: <var>result</var>'s <span
87063-
data-x="concept-module-script-instantiation-error">instantiation error</span>, [[Target]]:
87064-
empty }.</p></li>
87091+
<li><p>Let <var>record</var> be <var>result</var>'s <span
87092+
data-x="concept-module-script-module-record">module record</span>.</p></li>
8706587093

8706687094
<li>
87067-
<p>Otherwise:</p>
87068-
87069-
<ol>
87070-
<li><p>Let <var>record</var> be <var>result</var>'s <span
87071-
data-x="concept-module-script-module-record">module record</span>.</p></li>
87072-
87073-
<li>
87074-
<p>Set <var>instantiationStatus</var> to <var>record</var>.<span
87075-
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span>().</p>
87095+
<p>Let <var>instantiationStatus</var> be <var>record</var>.<span
87096+
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span>().</p>
8707687097

87077-
<p class="note">This step will recursively call <span
87078-
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span> all of the
87079-
module's uninstantiated dependencies.</p>
87080-
</li>
87081-
</ol>
87098+
<p class="note">This step will recursively call <span
87099+
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span> all of the
87100+
module's uninstantiated dependencies.</p>
8708287101
</li>
8708387102

8708487103
<li>
87085-
<p>For each <var>script</var> in <var>result</var>'s <span>uninstantiated inclusive descendant module
87086-
scripts</span>, perform the following steps:</p>
87104+
<p>For each <var>script</var> in <var>result</var>'s <span>uninstantiated inclusive descendant
87105+
module scripts</span>, perform the following steps:</p>
8708787106

8708887107
<ol>
87089-
<li>
87090-
<p>If <var>instantiationStatus</var> is an abrupt completion, then:</p>
87091-
87092-
<ol>
87093-
<li><p>Set <var>script</var> <span data-x="concept-module-script-module-record">module
87094-
record</span>'s [[HostDefined]] field to undefined.</p></li>
87095-
87096-
<li><p>Set <var>script</var>'s <span data-x="concept-module-script-module-record">module
87097-
record</span> to null.</p></li>
87098-
87099-
<li><p>Set <var>script</var>'s <span
87100-
data-x="concept-module-script-instantiation-state">instantiation state</span> to "<code
87101-
data-x="">errored</code>".</p></li>
87102-
87103-
<li><p>Set <var>script</var>'s <span
87104-
data-x="concept-module-script-instantiation-error">instantiation error</span> to
87105-
<var>instantiationStatus</var>.[[Value]].</p></li>
87106-
</ol>
87107-
</li>
87108+
<li><p>If <var>instantiationStatus</var> is an abrupt completion, then <span data-x="error a
87109+
module script">error</span> <var>script</var> with
87110+
<var>instantiationStatus</var>.[[Value]].</p></li>
8710887111

8710987112
<li><p>Otherwise, set <var>script</var>'s <span
87110-
data-x="concept-module-script-instantiation-state">instantiation state</span> to "<code
87113+
data-x="concept-module-script-state">state</span> to "<code
8711187114
data-x="">instantiated</code>".</p></li>
8711287115
</ol>
8711387116
</li>
@@ -87125,6 +87128,9 @@ interface <dfn>NavigatorOnLine</dfn> {
8712587128
data-x="module script">module scripts</span> determined as follows:</p>
8712687129

8712787130
<ol>
87131+
<li><p>If <var>script</var>'s <span data-x="concept-module-script-module-record">module
87132+
record</span> is null, return the empty set.</p></li>
87133+
8712887134
<li><p>Let <var>moduleMap</var> be <var>script</var>'s <span>settings object</span>'s
8712987135
<span data-x="concept-settings-object-module-map">module map</span>.</p></li>
8713087136

@@ -87183,7 +87189,7 @@ interface <dfn>NavigatorOnLine</dfn> {
8718387189
</li>
8718487190

8718587191
<li><p>Return a <span>set</span> containing all items of <var>inclusive descendants</var> whose
87186-
<span data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
87192+
<span data-x="concept-module-script-state">state</span> is "<code
8718787193
data-x="">uninstantiated</code>".</p></li>
8718887194
</ol>
8718987195

@@ -87316,10 +87322,11 @@ interface <dfn>NavigatorOnLine</dfn> {
8731687322
<ol>
8731787323
<li><p>Let <var>error</var> be a new <code>TypeError</code> exception.</p></li>
8731887324

87319-
<li><p><span>Report the exception</span> <var>error</var> for <var>module
87320-
script</var>.</p></li>
87325+
<li><p><span data-x="error a module script">Error</span> <var>module script</var> with
87326+
<var>error</var>.</p></li>
8732187327

87322-
<li><p>Abort this algorithm, and asynchronously complete it with null.</p></li>
87328+
<li><p>Abort this algorithm, and asynchronously complete it with <var>module
87329+
script</var>.</p></li>
8732387330
</ol>
8732487331
</li>
8732587332

@@ -87342,10 +87349,25 @@ interface <dfn>NavigatorOnLine</dfn> {
8734287349
<span data-x="fetching-scripts-perform-fetch">perform the fetch</span> steps, pass those along
8734387350
while performing the <span>internal module script graph fetching procedure</span>.</p>
8734487351

87345-
<p>Wait for all of the <span>internal module script graph fetching procedure</span> invocations
87346-
to asynchronously complete. If any of them asynchronously complete with null, then
87347-
asynchronously complete this algorithm with null. Otherwise, asynchronously complete this
87348-
algorithm with <var>module script</var>.</p>
87352+
<p>These invocations of the <span>internal module script graph fetching procedure</span> should
87353+
be performed in parallel to each other.</p>
87354+
87355+
<p>If any invocation of the <span>internal module script graph fetching procedure</span>
87356+
asynchronously completes with null, optionally abort all other invocations, and then
87357+
asynchronously complete this algorithm with null.</p>
87358+
87359+
<p>If any invocation of the <span>internal module script graph fetching procedure</span>
87360+
asynchronously completes with a <span>module script</span> whose <span
87361+
data-x="concept-module-script-state">state</span> is "<code data-x="">errored</code>",
87362+
optionally abort all other invocations, and then asynchronously complete this algorithm with
87363+
<var>module script</var>. (The errored descendant will cause errors later in the module-fetching
87364+
process, but for now we treat it as a premature "success".)</p>
87365+
87366+
<p>Otherwise, wait for all of the <span>internal module script graph fetching procedure</span>
87367+
invocations to asynchronously complete, with <span data-x="module script">module scripts</span>
87368+
whose <span data-x="concept-module-script-state">states</span> are not "<code
87369+
data-x="">errored</code>". Then, asynchronously complete this algorithm with <var>module
87370+
script</var>.</p>
8734987371
</li>
8735087372
</ol>
8735187373

@@ -87406,9 +87428,19 @@ interface <dfn>NavigatorOnLine</dfn> {
8740687428
<var>result</var>.[[HostDefined]] will be <var>script</var>.</p>
8740787429
</li>
8740887430

87409-
<li><p>If <var>result</var> is a <span>List</span> of errors, <span>report the exception</span>
87410-
given by the first element of <var>result</var> for <var>script</var>, return null, and abort
87411-
these steps.</p></li>
87431+
<li>
87432+
<p>If <var>result</var> is a <span>List</span> of errors, then:</p>
87433+
87434+
<ol>
87435+
<li><p><span data-x="error a module script">Error</span> <var>script</var> with
87436+
<var>errors</var>[0].</p></li>
87437+
87438+
<li><p>Return <var>script</var>.</p></li>
87439+
</ol>
87440+
</li>
87441+
87442+
<li><p>Set <var>script</var>'s <span data-x="concept-module-script-state">state</span> to "<code
87443+
data-x="">uninstantiated</code>".</p></li>
8741287444

8741387445
<li><p>Set <var>script</var>'s <span data-x="concept-module-script-module-record">module
8741487446
record</span> to <var>result</var>.</p></li>
@@ -87506,14 +87538,12 @@ interface <dfn>NavigatorOnLine</dfn> {
8750687538
<li><p><span>Check if we can run script</span> with <var>settings</var>. If this returns "do
8750787539
not run" then abort these steps.</p></li>
8750887540

87509-
<li><p>If <var>s</var>'s <span data-x="concept-module-script-instantiation-state">instantiation
87510-
state</span> is "<code data-x="">errored</code>", then <span>report the
87511-
exception</span> given by <var>s</var>'s <span
87512-
data-x="concept-module-script-instantiation-error">instantiation error</span> for <var>s</var>
87513-
and abort these steps.</p></li>
87541+
<li><p>If <var>s</var>'s <span data-x="concept-module-script-state">state</span> is "<code
87542+
data-x="">errored</code>", then <span>report the exception</span> given by <var>s</var>'s <span
87543+
data-x="concept-module-script-error">error</span> for <var>s</var> and abort these
87544+
steps.</p></li>
8751487545

87515-
<li><p>Assert: <var>s</var>'s <span
87516-
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
87546+
<li><p>Assert: <var>s</var>'s <span data-x="concept-module-script-state">state</span> is "<code
8751787547
data-x="">instantiated</code>" (and thus its <span
8751887548
data-x="concept-module-script-module-record">module record</span> is not null).</p></li>
8751987549

@@ -87527,13 +87557,24 @@ interface <dfn>NavigatorOnLine</dfn> {
8752787557
data-x="js-ModuleEvaluation">ModuleEvaluation</span>().</p>
8752887558

8752987559
<p class="note">This step will recursively evaluate all of the module's dependencies.</p>
87560+
87561+
<p>If <span data-x="js-ModuleEvaluation">ModuleEvaluation</span> fails to complete as a result
87562+
of the user agent <span data-x="abort a running script">aborting the running script</span>, then
87563+
set <var>evaluationStatus</var> to Completion { [[Type]]: throw, [[Value]]: a new
87564+
<span>"<code>QuotaExceededError</code>"</span> <code>DOMException</code>, [[Target]]: empty }.
8753087565
</li>
8753187566

87532-
<li><p>If <var>evaluationStatus</var> is an abrupt completion, then <span>report the
87533-
exception</span> given by <var>evaluationStatus</var>.[[Value]] for <var>s</var>. (Do not perform
87534-
this step if <span data-x="js-ModuleEvaluation">ModuleEvaluation</span> fails to complete as a
87535-
result of the user agent <span data-x="abort a running script">aborting the running
87536-
script</span>.)</p></li>
87567+
<li>
87568+
<p>If <var>evaluationStatus</var> is an abrupt completion, then:</p>
87569+
87570+
<ol>
87571+
<li><p><span data-x="error a module script">Error</span> <var>script</var> with
87572+
<var>evaluationStatus</var>.[[Value]].</p></li>
87573+
87574+
<li><p><span>Report the exception</span> given by <var>evaluationStatus</var>.[[Value]] for
87575+
<var>s</var>.</p>
87576+
</ol>
87577+
</li>
8753787578

8753887579
<li><p><span>Clean up after running script</span> with <var>settings</var>.</p></li>
8753987580
</ol>
@@ -88389,9 +88430,9 @@ import "https://example.com/foo/../module2.js";</pre>
8838988430
steps.</p></li>
8839088431

8839188432
<li><p>If <var>resolved module script</var>'s <span
88392-
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
88393-
data-x="">errored</code>", then throw <var>resolved module script</var>'s <span
88394-
data-x="concept-module-script-instantiation-error">instantiation error</span>.</p></li>
88433+
data-x="concept-module-script-state">state</span> is "<code data-x="">errored</code>", then throw
88434+
<var>resolved module script</var>'s <span
88435+
data-x="concept-module-script-error">error</span>.</p></li>
8839588436

8839688437
<li><p>Assert: <var>resolved module script</var>'s <span
8839788438
data-x="concept-module-script-module-record">module record</span> is not null.</p></li>

0 commit comments

Comments
 (0)