Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add requirements for ESM-supporting runtimes #49

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ Markup Shorthands: markdown yes
<pre class=link-defaults>
spec:url; type:interface; text:URL
spec:html; type:attribute; for:Window; text:navigator
spec:ecmascript; type:dfn; text:record
</pre>
<pre class="anchors">
urlPrefix: https://tc39.es/proposal-import-attributes/; spec: JSIMPORTATTRIBUTES
type: abstract-op
text: HostGetSupportedImportAttributes; url: sec-hostgetsupportedimportattributes
urlPrefix: https://html.spec.whatwg.org/multipage/; spec: html
type: dfn
text: fetch a single module script; url: fetch-a-single-module-script
text: fetch a single imported module script; url: fetch-a-single-imported-module-script
</pre>

Introduction {#intro}
Expand Down Expand Up @@ -90,6 +100,37 @@ The exact type of the `globalScope` can vary across runtimes. Most Web Platform

With many runtimes, adding a new global-scoped property can introduce breaking changes when the new global conflicts with existing application code. Many Web Platform APIs define global properties using the `readonly` attribute. To avoid introducing breaking changes, runtimes conforming to this specification MAY choose to ignore the `readonly` attribute for properties being added to the global scope.

Requirements for EcmaScript modules {#esm-requirements}
=======================================================

[=Web-interoperable runtimes=] which support EcmaScript modules must implement the following ECMA-262 host hooks as follows:

: [$HostLoadImportedModule$]
:: This host hook must be implemented [[HTML#hostloadimportedmodule|as defined in the HTML spec]], except that they may pass a [=perform the fetch hook=] algorithm to [=fetch a single imported module script=] even when <var ignore="">loadState</var> is undefined. (See also [[#custom-module-loading]].)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can this perform the fetch hook be obtained from? Somewhere globally available, or can it be potentially different per module?

Copy link
Member Author

@andreubotella andreubotella Jul 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention was to have a single "perform the fetch hook" algorithm per runtime, if that runtime needs or supports module loading customizations. But the intention was also for this spec change to be generic enough that it could cover npm imports and Node.js's custom loaders, but now that I look into it, even a per-module hook isn't enough for that because it doesn't override module resolution. I will think of other ways to make these customizations possible.

: [$HostGetSupportedImportAttributes$]
:: This host hook must be implemented [[HTML#hostgetsupportedimportattributes|as defined in the HTML spec]].

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prevents runtimes from supporting other attributes, rather than just making sure that they support type. Is it intended?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not intended, but the rest of HTML import algorithms don't support any attributes other than type, and the attributes are not passed to the perform the fetch hook, so there's no way to customize the import any further based on the attributes. Again, I will try to think of other ways to enable this.

: [$HostGetImportMetaProperties$]
:: If a runtime can never have an [=entrypoint module=] for any [=agent clusters=] (e.g. web browsers), then it may implement this host hook [[HTML#hostgetimportmetaproperties|as defined in the HTML spec]]. Otherwise, it must implement it as follows:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a runtime never has entry points, is there any observable difference between the HTML algorithm and the one below?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the algorithm below, import.meta.main will exist and be set to false for non-entrypoint modules, whereas with the HTML algorithm import.meta.main does not exist.

1. Let <var>moduleScript</var> be <var ignore="">moduleRecord</var>.\[[HostDefined]].
1. Let <var>urlString</var> and <var>resolveFunction</var> be [[HTML#hostgetimportmetaproperties|as defined in the HTML spec]].
1. Let <var>is main</var> be true if <var>moduleScript</var> is the [=surrounding agent=]'s [=agent cluster=]'s [=entrypoint module=]; false otherwise.
1. Return « [=Record=] { \[[Key]]: "<code>url</code>", \[[Value]]: <var>urlString</var> }, [=Record=] { \[[Key]]: "<code>resolve</code>", \[[Value]]: <var>resolveFunction</var> }, [=Record=] { \[[Key]]: "<code>main</code>", \[[Value]]: <var>is main</var> } ».
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to define more strictly what the resolveFunction implementation should look like? Like how many arguments does it take, and what its return value should look like. Asking because I think Node.js would like to have an optional second parameter to allow access to the resolve value from another module's perspective. Also it'd be convenient for us if the return value could be a URL instance.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See nodejs/modules#550 and whatwg/html#5572. Node has been engaging with WHATWG for years on this, and at this point I think we’ve accepted that we’re following whatever signature is allowed by the HTML spec. I would be nervous if WinterCG approved an API that differed from HTML’s.

We could perhaps introduce some new API, import.meta.resolveURL say, for a different variation.


A [=JavaScript module script=] is an [=agent cluster=]'s <dfn>entrypoint module</dfn> if both of the following conditions hold:
* The call to [=fetch a single module script=] that created it had <var ignore="">[=isTopLevel=]</var> set to true.
* That call happened before any other call to [=fetch a single module script=] or before any other JavaScript code was run in the [=agent cluster=].

For the purposes of this definition, runtime initialization code is ignored, even if it is written in JavaScript or uses [=module scripts=].

Issue: This definition does not actually exclude browsers, since the first user code run in an agent cluster might be a <code>&lt;script type="module"&gt;</code>.

Customizing module loading {#custom-module-loading}
---------------------------------------------------

[=Web-interoperable runtimes=] might want to customize the module loading process for EcmaScript modules, e.g. for allowing certain custom HTTP schemes such as <code>node:</code> or <code>npm:</code>, disallowing HTTP(S) imports, or transpiling non-JavaScript code.

They must do this by modifying [=fetch an external module script graph=], [=fetch a module worker script graph=] and [[HTML#hostloadimportedmodule|HostLoadImportedModule]] to pass a custom [=perform the fetch hook=] algorithm (only if <var ignore="">loadState</var> is undefined, in the case of HostLoadImportedModule).

Requirements for navigator.userAgent
====================================

Expand Down