Skip to content

Commit 3e48877

Browse files
authored
Handle module resolution when there is no active script
Closes #3295. This also fixes a related inaccurate assert in EnqueueJob, putting in guards for a null active script there as well and adding examples explaining the various scenarios.
1 parent 7663812 commit 3e48877

File tree

1 file changed

+129
-36
lines changed

1 file changed

+129
-36
lines changed

source

Lines changed: 129 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -86477,6 +86477,10 @@ interface <dfn>ApplicationCache</dfn> : <span>EventTarget</span> {
8647786477
<li><p>Return <var>record</var>.[[HostDefined]].</p></li>
8647886478
</ol>
8647986479

86480+
<p class="note">The <span>active script</span> concept is so far only used by the
86481+
<code>import()</code> feature, to determine the <span data-x="concept-script-base-url">base
86482+
URL</span> to use for resolving relative module specifiers.</p>
86483+
8648086484
<hr>
8648186485

8648286486
<p>An <dfn data-export="">environment</dfn> is an object that identifies the settings of a
@@ -88278,14 +88282,54 @@ document.querySelector("button").addEventListener("click", bound);
8827888282

8827988283
<li><p>Let <var>active script</var> be the <span>active script</span>.</p></li>
8828088284

88281-
<li><p>Assert: <var>active script</var> is not null, as jobs are only enqueued by the JavaScript
88282-
specification while a script is active.</p></li>
88285+
<li><p>Let <var>script execution context</var> be null.</p></li>
8828388286

88284-
<li><p>Let <var>script execution context</var> be a new <span>JavaScript execution
88285-
context</span>, with its Function field set to null, its Realm field set to <var>active
88286-
script</var>'s <span>settings object</span>'s <span data-x="environment settings object's
88287-
Realm">Realm</span>, and its ScriptOrModule set to <var>active script</var>'s <span
88288-
data-x="concept-script-record">record</span>.</p></li>
88287+
<li>
88288+
<p>If <var>active script</var> is not null, set <var>script execution context</var> to a new
88289+
<span>JavaScript execution context</span>, with its Function field set to null, its Realm field
88290+
set to <var>active script</var>'s <span>settings object</span>'s <span data-x="environment
88291+
settings object's Realm">Realm</span>, and its ScriptOrModule set to <var>active script</var>'s
88292+
<span data-x="concept-script-record">record</span>.</p>
88293+
88294+
<p class="note">As seen below, this is used in order to propagate the current <span>active
88295+
script</span> forward to the time when the job is executed.</p>
88296+
88297+
<div class="example">
88298+
<p>A case where <var>active script</var> is non-null, and saving it in this way is useful, is
88299+
the following:</p>
88300+
88301+
<pre><code class="js" data-x="">Promise.resolve('import(`./example.mjs`)').then(eval);</code></pre>
88302+
88303+
<p>Without this step (and the steps below that use it), there would be no <span>active
88304+
script</span> when the <code>import()</code> expression is evaluated, since <code>eval()</code>
88305+
is a built-in function that does not originate from any particular <span
88306+
data-x="concept-script">script</span>.</p>
88307+
88308+
<p>With this step in place, the active script is propagated from the above code into the job,
88309+
allowing <code>import()</code> to use the original script's <span
88310+
data-x="concept-script-base-url">base URL</span> appropriately.</p>
88311+
</div>
88312+
88313+
<div class="example">
88314+
<p><var>active script</var> can be null if the user clicks on the following button, before any
88315+
script ever accesses the button's <code data-x="">onclick</code> property:</p>
88316+
88317+
<pre><code class="html" data-x="">&lt;button onclick="Promise.resolve('import(`./example.mjs`)').then(eval)">Click me&lt;/button></code></pre>
88318+
88319+
<p>In this case, the JavaScript function for the <span data-x="event handlers">event
88320+
handler</span> will be created by the <span data-x="getting the current value of the event
88321+
handler">get the current value of the event handler</span> algorithm as a direct result of user
88322+
action, with no script on the stack (i.e., no <span>active script</span>). Thus, when the
88323+
promise machinery calls <span>EnqueueJob</span>, there will be no <span>active script</span> to
88324+
pass along.</p>
88325+
88326+
<p>As a consequence, this means that when the <code>import()</code> expression is evaluated,
88327+
there will still be no <span>active script</span>. Fortunately that is handled by our
88328+
implementations of <span>HostResolveImportedModule</span> and
88329+
<span>HostImportModuleDynamically</span>, by falling back to using the <span>current settings
88330+
object</span>'s <span>API base URL</span>.</p>
88331+
</div>
88332+
</li>
8828988333

8829088334
<li>
8829188335
<p><span>Queue a microtask</span>, on <var>job settings</var>'s <span>responsible event
@@ -88310,20 +88354,20 @@ document.querySelector("button").addEventListener("click", bound);
8831088354
</li>
8831188355

8831288356
<li>
88313-
<p><span data-x="stack push">Push</span> <var>script execution context</var> onto the
88314-
<span>JavaScript execution context stack</span>.</p>
88357+
<p>If <var>script execution context</var> is not null, then <span data-x="stack
88358+
push">push</span> <var>script execution context</var> onto the <span>JavaScript execution
88359+
context stack</span>.</p>
8831588360

88316-
<p class="note">This affects the <span>active script</span> while the job runs, in cases like
88317-
<code data-x="">Promise.resolve("...").then(eval)</code> where there would otherwise be no
88318-
active script since <code>eval()</code> is a built-in function that does not originate from
88319-
any particular <span data-x="concept-script">script</span>.</p>
88361+
<p class="note">As explained above, this affects the <span>active script</span> while the job
88362+
runs.</p>
8832088363
</li>
8832188364

8832288365
<li><p>Let <var>result</var> be the result of performing the abstract operation specified by
8832388366
<var>job</var>, using the elements of <var>arguments</var> as its arguments.</p></li>
8832488367

88325-
<li><p><span data-x="stack pop">Pop</span> <var>script execution context</var> from the
88326-
<span>JavaScript execution context stack</span>.</p></li>
88368+
<li><p>If <var>script execution context</var> is not null, then <span data-x="stack
88369+
pop">pop</span> <var>script execution context</var> from the <span>JavaScript execution context
88370+
stack</span>.</p></li>
8832788371

8832888372
<li><p><span>Clean up after running a callback</span> with <var>incumbent
8832988373
settings</var>.</p></li>
@@ -88470,20 +88514,48 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
8847088514
implementation: <ref spec=JAVASCRIPT> <ref spec=JSIMPORT></p>
8847188515

8847288516
<ol>
88473-
<li><p>Let <var>referencing script</var> be
88474-
<var>referencingScriptOrModule</var>.[[HostDefined]].</p></li>
88517+
<li><p>Let <var>settings object</var> be the <span>current settings object</span>.</p></li>
8847588518

88476-
<li><p>Let <var>moduleMap</var> be <var>referencing script</var>'s <span>settings object</span>'s
88477-
<span data-x="concept-settings-object-module-map">module map</span>.</p></li>
88519+
<li><p>Let <var>base URL</var> be <var>settings object</var>'s <span>API base
88520+
URL</span>.</p></li>
88521+
88522+
<li>
88523+
<p>If <var>referencingScriptOrModule</var> is not null, then:</p>
88524+
88525+
<ol>
88526+
<li><p>Let <var>referencing script</var> be
88527+
<var>referencingScriptOrModule</var>.[[HostDefined]].</p></li>
88528+
88529+
<li><p>Set <var>settings object</var> to <var>referencing script</var>'s <span>settings
88530+
object</span>.</p></li>
88531+
88532+
<li><p>Set <var>base URL</var> to <var>referencing script</var>'s <span
88533+
data-x="concept-script-base-url">base URL</span>.</p></li>
88534+
</ol>
88535+
88536+
<div class="example">
88537+
<p><var>referencingScriptOrModule</var> is not usually null. One case where it <em>can</em> be
88538+
null is if the user clicks the control in the following example:</p>
88539+
88540+
<pre><code class="html" data-x="">&lt;button onclick="import('./foo.mjs')">Click me&lt;/button></code></pre>
88541+
88542+
<p>In this case, at the time the <code>import()</code> expression runs,
88543+
<span>GetActiveScriptOrModule</span> will return null, which will be passed to this abstract
88544+
operation when <span data-x="js-HostResolveImportedModule">HostResolveImportedModule</span> is
88545+
called by <span>FinishDynamicImport</span>.</p>
88546+
</div>
88547+
</li>
88548+
88549+
<li><p>Let <var>moduleMap</var> be <var>settings object</var>'s <span
88550+
data-x="concept-settings-object-module-map">module map</span>.</p></li>
8847888551

8847988552
<li><p>Let <var>url</var> be the result of <span data-x="resolve a module specifier">resolving a
88480-
module specifier</span> given <var>referencing script</var>'s <span
88481-
data-x="concept-script-base-url">base URL</span> and <var>specifier</var>.</p></li>
88553+
module specifier</span> given <var>base URL</var> and <var>specifier</var>.</p></li>
8848288554

8848388555
<li><p>Assert: <var>url</var> is never failure, because <span data-x="resolve a module
88484-
specifier">resolving a module specifier</span> must have been <a
88485-
href="#validate-requested-module-specifiers">previously successful</a> with these
88486-
same two arguments.</p></li>
88556+
specifier">resolving a module specifier</span> must have been previously successful with these
88557+
same two arguments (either <a href="#validate-requested-module-specifiers">while creating the
88558+
corresponding module script</a>, or in <span>HostImportModuleDynamically</span>).</p></li>
8848788559

8848888560
<li><p>Let <var>resolved module script</var> be <var>moduleMap</var>[<var>url</var>]. (This entry
8848988561
must <span data-x="map exists">exist</span> for us to have gotten to this point.)</p></li>
@@ -88506,12 +88578,38 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
8850688578
User agents must use the following implementation: <ref spec=JSIMPORT></p>
8850788579

8850888580
<ol>
88509-
<li><p>Let <var>referencing script</var> be
88510-
<var>referencingScriptOrModule</var>.[[HostDefined]].</p></li>
88581+
<li><p>Let <var>settings object</var> be the <span>current settings object</span>.</p></li>
88582+
88583+
<li><p>Let <var>base URL</var> be <var>settings object</var>'s <span>API base
88584+
URL</span>.</p></li>
88585+
88586+
<li><p>Let <var>fetch options</var> be the <span>default classic script fetch
88587+
options</span>.</p></li>
88588+
88589+
<li>
88590+
<p>If <var>referencingScriptOrModule</var> is not null, then:</p>
88591+
88592+
<ol>
88593+
<li><p>Let <var>referencing script</var> be
88594+
<var>referencingScriptOrModule</var>.[[HostDefined]].</p>
88595+
88596+
<li><p>Set <var>settings object</var> to <var>referencing script</var>'s <span>settings
88597+
object</span>.</p></li>
88598+
88599+
<li><p>Set <var>base URL</var> to <var>referencing script</var>'s <span
88600+
data-x="concept-script-base-url">base URL</span>.</p></li>
88601+
88602+
<li><p>Set <var>fetch options</var> to the <span>descendant script fetch options</span> for
88603+
<var>referencing script</var>'s <span data-x="concept-script-script-fetch-options">fetch
88604+
options</span>.</p></li>
88605+
</ol>
88606+
88607+
<p class="note">As explained above for <span>HostResolveImportedModule</span>, in the common
88608+
case, <var>referencingScriptOrModule</var> is non-null.</p>
88609+
</li>
8851188610

8851288611
<li><p>Let <var>url</var> be the result of <span data-x="resolve a module specifier">resolving a
88513-
module specifier</span> given <var>referencing script</var>'s <span
88514-
data-x="concept-script-base-url">base URL</span> and <var>specifier</var>.</p></li>
88612+
module specifier</span> given <var>base URL</var> and <var>specifier</var>.</p></li>
8851588613

8851688614
<li>
8851788615
<p>If <var>url</var> is failure, then:</p>
@@ -88527,14 +88625,9 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
8852788625
</ol>
8852888626
</li>
8852988627

88530-
<li><p>Let <var>options</var> be the <span>descendant script fetch options</span> for
88531-
<var>referencing script</var>'s <span data-x="concept-script-script-fetch-options">fetch
88532-
options</span>.</p></li>
88533-
88534-
<li><p><span>Fetch a module script graph</span> given <var>url</var>, <var>referencing
88535-
script</var>'s <span>settings object</span>, "<code data-x="">script</code>", and
88536-
<var>options</var>. Wait until the algorithm asynchronously completes with
88537-
<var>result</var>.</p></li>
88628+
<li><p><span>Fetch a module script graph</span> given <var>url</var>, <var>settings object</var>,
88629+
"<code data-x="">script</code>", and <var>fetch options</var>. Wait until the algorithm
88630+
asynchronously completes with <var>result</var>.</p></li>
8853888631

8853988632
<li>
8854088633
<p>If <var>result</var> is null, then:</p>

0 commit comments

Comments
 (0)