From bf7e522a768f25119240c469cbd8c3e5b7ffe5d0 Mon Sep 17 00:00:00 2001 From: Daniel Clark Date: Fri, 8 Feb 2019 16:34:43 -0800 Subject: [PATCH 1/6] Rebasing ES spec changes on https://github.com/tc39/ecma262/pull/1311. Misc other fixes/refactorings. --- proposals/html-module-spec-changes.md | 105 ++++++++++++++++---------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/proposals/html-module-spec-changes.md b/proposals/html-module-spec-changes.md index 0807cec1..51632dd9 100644 --- a/proposals/html-module-spec-changes.md +++ b/proposals/html-module-spec-changes.md @@ -5,41 +5,45 @@ Questions/corrections/feedback are welcome! I've left TODOs in several places w     [@bocupp](https://github.com/BoCupp) [@samsebree](https://github.com/samsebree) [@travisleithead](https://github.com/travisleithead) # ES6 Spec Changes ([full spec link](https://tc39.github.io/ecma262/)): -- Introduce a new subtype of [Abstract Module Record](https://tc39.github.io/ecma262/#sec-abstract-module-records) in addition to the existing [Source Text Module Record](https://tc39.github.io/ecma262/#sourctextmodule-record). Proposed name for the new subtype is HTML Module Record. - 1. HTML Module record has these fields in common with Source Text Module Record (perhaps they should move up to Abstract Module Record): [[Status]], [[EvaluationError]], [[DFSIndex]], [[DFSAncestorIndex]]. - 2. In addition HTML Module Records have this new field: - [[RequestedModules]]: A list of ScriptEntry records, appearing in document order per the position of the corresponding script elements in the HTML Document. ScriptEntry is defined as: + +These spec changes are built on top of the proposed refactoring here: https://github.com/tc39/ecma262/pull/1311 + +- Introduce a new subtype of Cyclic Module Record in addition to the existing [Source Text Module Record](https://tc39.github.io/ecma262/#sourctextmodule-record), named HTML Module Record. + 1. HTML Module Records reuse the [[RequestedModules]] field of Cyclic Module Record, but instead of a list of strings it is a list of ScriptEntry records. See definition of HostParseHTMLModule in HTML5 spec changes for a specification of how these are populated. + _[TODO: This reuse-name-with-different-type is pretty fishy. Should [[RequestedModules]] in Cyclic MR be generalized as a list that can hold objects of a type specified in each subclass? Or should we use an entirely new field in HTML MR? Or should we generate unique IDs for the inline script elements and place them in the Module Map, so that an HTML Module Record can just use strings in [[RequestedModules]]?]._ + ScriptEntry is defined as: | Field Name | Value Type | Meaning | | --- | --- | --- | - | [[IsInline]] |bool | Is this entry from an inline script? | - | [[ModuleRecord]] | Source Text Module Record \| null | The source text module record for the script element if IsInline == true | - | [[SourceName]] | String \| null | The name specified in the script’s src attribute if IsInline == false. Null otherwise. | - 3. Additionally, the [[HostDefined]] field in Abstract Module Record should be used to hold the document, or an HTML Module object on the HTML5 spec side that will hold the document. It’s basically meant as an abstract container for the HTML5 spec side of things to stash data that it defines -- for script modules this holds the [module script](https://html.spec.whatwg.org/multipage/webappapis.html#module-script) as defined in the HTML5 spec. -- HTML Module record should have a modified version of [InnerModuleInstantiation](https://tc39.github.io/ecma262/#sec-innermoduleinstantiation). In short, the existing definition of this function recursively calls InnerModuleInstantiation on each child module (calling [HostResolveImportedModule](https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule) to resolve module names to Source Text Module Records), then calls [ModuleDeclarationEnvironmentSetup](https://tc39.github.io/ecma262/#sec-moduledeclarationenvironmentsetup) to set up the lexical environment and resolve imports/exports for the current module. In order to follow the structure of the newly defined ScriptEntry record as defined above, we will change the current definition of InnerModuleInstantiation’s step 9 (“For each string required that is an element of module.[[RequestedModules]]...) + | [[InlineModuleRecord]] | Module Record \| null | The Source Text Module Record for the module request if it was avaiable at parse time. Null otherwise. | + | [[ExternalScriptURL]] | String \| null | The URL for the module request if the Module Record was not available at parse time. Null otherwise. | + 2. The [[HostDefined]] field in Abstract Module Record will be set to the HTML Module Script (see HTML5 Spec changes). This is analogous to script modules where this field holds the JavaScript [module script](https://html.spec.whatwg.org/multipage/webappapis.html#module-script) as defined in the HTML5 spec. +- HTML Module Record inherits the concrete Instantiate() method from Cyclic Module Record. +- HTML Module Record defines its own version of [InnerModuleInstantiation](https://tc39.github.io/ecma262/#sec-innermoduleinstantiation). Cyclic Module Record's definition recursively calls InnerModuleInstantiation on each child module (calling [HostResolveImportedModule](https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule) to resolve module names to Module Records), then calls [ModuleDeclarationEnvironmentSetup](https://tc39.github.io/ecma262/#sec-moduledeclarationenvironmentsetup) to set up the lexical environment and resolve imports/exports for the current module. HTML Module Record's version will be similar, but will change the definition of step 9 (“For each string required that is an element of module.[[RequestedModules]]...) in order to follow the structure of the newly defined ScriptEntry record as defined above. - 9\. For each ScriptEntry *se* in *module*.[[RequestedModules]]) - a\. Let *requiredModule* be null. - - b\. If *se*.[[IsInline]]) == true - - i\. Let *requiredModule* be (*se*.[[ModuleRecord]]). + - b\. If *se*.[[InlineModuleRecord]]) != null + - i\. Let *requiredModule* be (*se*.[[InlineModuleRecord]]). - c\. Else - - i\. Let *requiredModule* be HostResolveImportedModule(*module*, *se*.[[SourceName]]) + - i\. Let *requiredModule* be HostResolveImportedModule(*module*, *se*.[[ExternalScriptURL]]) - d\. Set *index* to ? InnerModuleInstantiation(*requiredModule*, *stack*, *index*). - e\. Assert: *requiredModule*.[[Status]] is either "instantiating", "instantiated", or "evaluated". - f\. Assert: *requiredModule*.[[Status]] is "instantiating" if and only if *requiredModule* is in *stack*. - g\. If *requiredModule*.[[Status]] is "instantiating", then - i\. Assert: *requiredModule* is a Source Text Module Record. - ii\. Set *module*.[[DFSAncestorIndex]] to min(*module*.[[DFSAncestorIndex]], *requiredModule*.[[DFSAncestorIndex]]). -- HTML Module record should implement a modified version of [ModuleDeclarationEnvironmentSetup](https://tc39.github.io/ecma262/#sec-moduledeclarationenvironmentsetup). Called from InnerModuleInstantiation, this function sets up the lexical environment and resolves imports/exports for the current module. For HTML Modules, there is no distinct lexical environment so we may just redefine this to be a no-op, or further modify the HTML Module version of InnerModuleInstantiation to skip it altogether. Note that the ‘export * from all inline script elements’ stuff is performed in our redefined [ResolveExport](https://tc39.github.io/ecma262/#sec-resolveexport) below. +- HTML Module Record provides a concrete implementation of InitializeEnvironment(), implementing the corresponding abstract method on Cyclic Module Record. The implementation is just a no-op. The Source Text Module Record version of this method sets up the lexical environment and resolves imports/exports for the current module, but for HTML modules there is no distinct lexical environment so there is nothing to do. +- HTML Module Record provides a concrete implementation of ExecuteModule(), implementing the corresponding abstract method on Cyclic Module Record. The implementation is just a no-op. The Source Text Module Record version of this method initializes the execution context of the module and executes its code, but HTML modules have no code of their own to execute so there is nothing to do. - HTML Module Record should implement a modified version of [GetExportedNames](https://tc39.github.io/ecma262/#sec-getexportednames)(*exportStarSet*), as follows: - - 1\. Let *module* be this Source Text Module Record. + - 1\. Let *module* be this HTML Module Record. - 2\. If *exportStarSet* contains *module*, then - a\. Assert: We've reached the starting point of an import * circularity. - b\. Return a new empty List. - 3\. Append *module* to *exportStarSet*. - 4\. Let *exportedNames* be a new empty List. - 5\. For each ScriptEntry *se* in *module*.[[RequestedModules]]), do: - - a\. If *se*.[[IsInline]] == true: - - i\. Let *starNames* be *se*.[[ModuleRecord]].GetExportedNames(*exportStarSet*). + - a\. If *se*.[[InlineModuleRecord]] != nullInlineModuleRecord: + - i\. Let *starNames* be *se*.[[InlineModuleRecord]].GetExportedNames(*exportStarSet*). - ii\. For each element *n* of *starNames*, do - a\. If SameValue(*n*, "default") is false, then - i\. If *n* is not an element of *exportedNames*, then @@ -53,12 +57,12 @@ Questions/corrections/feedback are welcome! I've left TODOs in several places w - ii\. Return null. - 3\. Append the Record { [[Module]]: *module*, [[ExportName]]: *exportName* } to resolveSet. - 4\. If SameValue(*exportName*, "default") is true, then - - a\. Return the HTML Document associated with this HTML Module record. TODO How do we actually return this as a resolved binding if the HTML record has no lexical scope? Maybe the record needs to have one? + - a\. Return the HTML Document associated with this HTML Module record. - b\. NOTE: I assume here that we’re not trying to pass through default exports of the inline scripts. - 5\. Let *starResolution* be null. - 6\. For each ScriptEntry record *se* in *module*.[[RequestedModules]], do: - - a\. If *se*.[[IsInline]] == false, continue to next record. - - b\. Let *importedModule* be *se*.[[ModuleRecord]]). + - a\. If *se*.[[InlineModuleRecord]] == null, continue to next record. + - b\. Let *importedModule* be *se*.[[InlineModuleRecord]]). - c\. Let *resolution* be ? importedModule.ResolveExport(*exportName*, *resolveSet*). - d\. If *resolution* is "**ambiguous**", return "**ambiguous**". - e\. If *resolution* is not null, then @@ -68,49 +72,68 @@ Questions/corrections/feedback are welcome! I've left TODOs in several places w - a\. Assert: There is more than one inline script that exports the requested name. - b\. Return "**ambiguous**". - 7\. Return *starResolution*. -- We need to redefine how the HTML Module is created and its fields are populated. Instead of populating the fields in [ParseModule](https://tc39.github.io/ecma262/#sec-parsemodule), we will create the module based on input from the result of parsing the HTML Document on the HTML5 side. See HTML5 spec proposed changes below. +- HTML Module Record inherits the concrete Evaluate() method from Cyclic Module Record. - HTML Module Record should implement a modified version of [InnerModuleEvaluation](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script)(*module*, *stack*, *index*). This method calls InnerModuleEvaluation on each child module, then executes the current module. The HTML Module version will have the following changes: - Change step 10 and step 10a to be the following, to account for the different structure of HTML Module Record vs Source Text Module Record. Steps 10b-10f remain the same: - 10\. For each ScriptEntry *se* in *module*.[[RequestedModules]]), do: - - a\. If (*se*.[[IsInline]] == true), let *requiredModule* be *se*.[[ModuleRecord]], else let *requiredModule* be HostResolveImportedModule(*module*, *se*.[[SourceName]]) + - a\. If (*se*.[[InlineModuleRecord]] != null), let *requiredModule* be *se*.[[InlineModuleRecord]], else let *requiredModule* be HostResolveImportedModule(*module*, *se*.[[ExternalScriptURL]]) - Omit step 11 (since the HTML module doesn’t have any JS code of its own to run; it only recurses to run the code of its requested modules per step 10). - + - Declare an implementation-defined abstract operation HostParseHTMLModule(*source*, *realm*, *htmlModule*). This operation will create an instance of HTML Module Record and populate its fields. See HTML5 spec changes below for the concrete implementation. + # HTML5 spec changes ([full spec link](https://html.spec.whatwg.org/)): -- Broadly speaking, the language throughout most of the module fetching algos ([[1](https://html.spec.whatwg.org/#fetch-a-module-script-graph)], [[2](https://html.spec.whatwg.org/#internal-module-script-graph-fetching-procedure)], [[3](https://html.spec.whatwg.org/#fetch-a-single-module-script)], [[4](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script)], [[5](https://html.spec.whatwg.org/#fetch-the-descendants-of-and-instantiate-a-module-script)], [[6](https://html.spec.whatwg.org/#finding-the-first-parse-error)]) needs to be generalized from “module script” to “module”, e.g. s/fetch a single module script/fetch a single module/. +- Introduce a third type of [script](https://html.spec.whatwg.org/multipage/webappapis.html#concept-script) named HTML Module Script. It has the following item in addition to script: + - A `document`: The [Document](https://html.spec.whatwg.org/multipage/dom.html#document) for the HTML Module, or null. +- Rename the existing concept of [module script](https://html.spec.whatwg.org/multipage/webappapis.html#module-script) to JavaScript module script. +- Redefine "module script" as a union of JavaScript module script or HTML module script. + - Broadly speaking, the usage of "module script" in most of the module fetching algos ([[1](https://html.spec.whatwg.org/#fetch-a-module-script-graph)], [[2](https://html.spec.whatwg.org/#internal-module-script-graph-fetching-procedure)], [[3](https://html.spec.whatwg.org/#fetch-a-single-module-script)], [[4](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script)], [[5](https://html.spec.whatwg.org/#fetch-the-descendants-of-and-instantiate-a-module-script)], [[6](https://html.spec.whatwg.org/#finding-the-first-parse-error)]) will refer to this new definition of module script, as they will be generalized to both HTML and JavaScript modules. - In [prepare a script](https://html.spec.whatwg.org/#prepare-a-script), when defining a script’s type in step 7, always set it to “module” if we’re parsing an HTML Module. TODO How to determine that? New parser flag? -- Introduce a “create an HTML Module”, similar to [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). The definition would look something like this: - - To create an HTML module, given a JavaScript string *source*, an environment settings object *settings*, a URL *baseURL*, and some script fetch options *options*: - - 1\. Let *htmlModule* be a new HTML Module that this algorithm will subsequently initialize. +- Rename [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script) to "create a JavaScript module script". +- Introduce a new algorithm “create an HTML module script”, similar to [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). The definition would look something like this: + - To create an HTML module script, given a JavaScript string *source*, an environment settings object *settings*, a URL *baseURL*, and some script fetch options *options*: + - 1\. Let *htmlModule* be a new HTML module script that this algorithm will subsequently initialize. - 2\. Set *htmlModule’s* settings object to *settings*. - 3\. Set *htmlModule’s* *base URL* to *baseURL*. - 4\. Set *htmlModule’s* fetch options to *options*. - 5\. Set *htmlModule's* *parse error* and *error to rethrow* to null. - 6\. Let *result* be ParseHTMLModule(*source*, *settings's* Realm, *htmlModule*). Note: Passing *htmlModule* as the last parameter here ensures *result*.[[HostDefined]] will be *htmlModule*. See below bullet for ParseHTMLModule definition. - - 7\. For each ScriptEntry *required* of *result*.[[RequestedModules]], such that *required*[[IsInline]] == false: - - a\. Let *url* be the result of resolving a module specifier given *htmlModule’s* *base URL* and *required*[[SourceName]]. + - 7\. For each ScriptEntry *required* of *result*.[[RequestedModules]], such that *required*[[InlineModuleRecord]] == null: + - a\. Let *url* be the result of resolving a module specifier given *htmlModule’s* *base URL* and *required*[[ExternalScriptURL]]. - b\. If *url* is failure, then: - i\. Let *error* be a new TypeError exception. - ii\. Set *htmlModule’s* *parse error* to *error*. - iii\. Return *htmlModule*. Note: This step is essentially validating all of the requested module specifiers. We treat a module with unresolvable module specifiers the same as one that cannot be parsed; in both cases, a syntactic issue makes it impossible to ever contemplate instantiating the module later. - 8\. Set *htmlModule’s* *record* to *result*. - 9\. Return *htmlModule*. -- Define ParseHTMLModule(*source*, *realm*, *htmlModule*) as roughly the following. TODO Given that we define HTML Module Record in ES6, should this function be defined over there? We’re using the HTML5 parser though... - - 1\. Let *record* be a new HTML Module record that this algorithm will subsequently initialize. - - 2\. Run the HTML5 parser on source to obtain the result *document*. +- Provide an implementation of the abstract operation HostParseHTMLModule(*source*, *realm*, *htmlModule*) as the following. + - 1\. Let *record* be a new HTML Module Record that this algorithm will subsequently initialize. + - 2\. Run the HTML5 parser on *source* to obtain the result *document*. - 3\. Set *record*.[[HostDefined]] = *htmlModule*. - 4\. For each HTMLScriptElement *script* in *document*: - a\. Let *se* be a new ScriptEntry record (see definition in ES6 changes above). - b\. If *script* is inline: - - i\. Set *se*[[IsInline]] = true - - ii\. Set *se*[[RequestedModule]] = *script’s* Source Text Module Record - - iii\. Set *se*[[SourceName]] = null + - i\. Set *se*[[InlineModuleRecord]] = *script’s* Source Text Module Record + - ii\. Set *se*[[ExternalScriptURL]] = null - c\. Else - - i\. Set *se*[[IsInline]] = false - - ii\. Set *se*[[RequestedModule]] = null - - iii\. Set *se*[[SourceName]] = *script’s* src URL + - i\. Set *se*[[InlineModuleRecord]] = null + - ii\. Set *se*[[ExternalScriptURL]] = *script’s* src URL - d\. Append *se* to *record*.[[RequestedModules]] - 5\. Return *record*. -- Change fetch a [single module script](https://html.spec.whatwg.org/#fetch-a-single-module-script) as follows: - - In step 9, allow HTML MIME type through in addition to JavaScript. - - In step 11, don’t unconditionally [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). Instead, key off the MIME type extracted in step 9, creating an HTML Module instead if we have an HTML MIME type. -- Change step 5 of [fetch the descendants of a module script](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script) such that when record is an HTML Module, use [[SourceName]] from each *record*.[[RequestedModules]] instead of the Source Text Module Record field *record*.[[RequestedModules]]. This change basically just accounts for the differences in how Source Text Module Record and HTML Module Record store their descendant module URLs. +- Change [fetch a single module script](https://html.spec.whatwg.org/#fetch-a-single-module-script) as follows: + - In step 9, allow `text/html` type through in addition to JavaScript. + - In step 11, don’t unconditionally [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). Instead, key off the MIME type extracted in step 9, creating an HTML Module instead if we have a `text/html` MIME type. +- Replace step 5 of [fetch the descendants of a module script](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script) with the following steps: + - 5\. If *module script* is a JavaScript module script, then: + - 1\. [For each](https://infra.spec.whatwg.org/#list-iterate) string *requested* of *record*.[[RequestedModules]], + - 1\. Let *url* be the result of [resolving a module specifier](https://html.spec.whatwg.org/#resolve-a-module-specifier) given *module script*'s [base URL](https://html.spec.whatwg.org/#concept-script-base-url) and *requested*. + - 2\. Assert: *url* is never failure, because [resolving a module specifier](https://html.spec.whatwg.org/#resolve-a-module-specifier) must have been [previously successful](https://html.spec.whatwg.org/#validate-requested-module-specifiers) with these same two arguments. + - 3\. If *visited set* does not [contain](https://infra.spec.whatwg.org/#list-contain) *url*, then: + - 1\. [Append](https://infra.spec.whatwg.org/#list-append) *url* to *urls*. + - 2\. [Append](https://infra.spec.whatwg.org/#list-append) *url* to *visited set*. + - 6\. Otherwise, *module script* is an HTML module script. Perform the following steps: + - 1\. [For each](https://infra.spec.whatwg.org/#list-iterate) ScriptEntry *entry* of *record*.[[RequestedModules]], + - 1\. If *entry*.[[ExternalScriptURL]] != null, then: + - 1\. Let *url* be the result of [resolving a module specifier](https://html.spec.whatwg.org/#resolve-a-module-specifier) given *module script*'s [base URL](https://html.spec.whatwg.org/#concept-script-base-url) and *entry*.[[ExternalScriptURL]]. + - 2\. Assert: *url* is never failure, because [resolving a module specifier](https://html.spec.whatwg.org/#resolve-a-module-specifier) must have been [previously successful](https://html.spec.whatwg.org/#validate-requested-module-specifiers) with these same two arguments. + - 3\. If *visited set* does not [contain](https://infra.spec.whatwg.org/#list-contain) *url*, then: + - 1\. [Append](https://infra.spec.whatwg.org/#list-append) *url* to *urls*. + - 2\. [Append](https://infra.spec.whatwg.org/#list-append) *url* to *visited set*. From c56572bf1c3208eb2b73bc618915ceb26dd4e34e Mon Sep 17 00:00:00 2001 From: Daniel Clark Date: Mon, 11 Feb 2019 16:08:02 -0800 Subject: [PATCH 2/6] Update ParseHTMLModule to populate missing fields and update HTML MR InitializeEnvironment to create *default* binding for default export of document --- proposals/html-module-spec-changes.md | 29 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/proposals/html-module-spec-changes.md b/proposals/html-module-spec-changes.md index 51632dd9..bc4eb8e9 100644 --- a/proposals/html-module-spec-changes.md +++ b/proposals/html-module-spec-changes.md @@ -32,7 +32,16 @@ These spec changes are built on top of the proposed refactoring here: https://gi - g\. If *requiredModule*.[[Status]] is "instantiating", then - i\. Assert: *requiredModule* is a Source Text Module Record. - ii\. Set *module*.[[DFSAncestorIndex]] to min(*module*.[[DFSAncestorIndex]], *requiredModule*.[[DFSAncestorIndex]]). -- HTML Module Record provides a concrete implementation of InitializeEnvironment(), implementing the corresponding abstract method on Cyclic Module Record. The implementation is just a no-op. The Source Text Module Record version of this method sets up the lexical environment and resolves imports/exports for the current module, but for HTML modules there is no distinct lexical environment so there is nothing to do. +- HTML Module Record provides a concrete implementation of InitializeEnvironment(), implementing the corresponding abstract method on Cyclic Module Record. This function is responsible for creating a mutable binding with the name "*default*" that will be used to set up the HTML Module's document as the module's default export. + 1. Let _module_ be this HTML Module Record. + 1. Let _realm_ be _module_.[[Realm]]. + 1. Assert: _realm_ is not *undefined*. + 1. Let _env_ be NewModuleEnvironment(_realm_.[[GlobalEnv]]). + 1. Set _module_.[[Environment]] to _env_. 1. Let _envRec_ be _env_'s EnvironmentRecord. + 1. Perform ! _envRec_.CreateMutableBinding("\*default\*", *false*). TODO Should this be CreateImmutableBinding? + 1. Call _envRec_.InitializeBinding("\*default\*", *undefined*). + 1. Return NormalCompletion(~empty~). + - HTML Module Record provides a concrete implementation of ExecuteModule(), implementing the corresponding abstract method on Cyclic Module Record. The implementation is just a no-op. The Source Text Module Record version of this method initializes the execution context of the module and executes its code, but HTML modules have no code of their own to execute so there is nothing to do. - HTML Module Record should implement a modified version of [GetExportedNames](https://tc39.github.io/ecma262/#sec-getexportednames)(*exportStarSet*), as follows: - 1\. Let *module* be this HTML Module Record. @@ -57,8 +66,9 @@ These spec changes are built on top of the proposed refactoring here: https://gi - ii\. Return null. - 3\. Append the Record { [[Module]]: *module*, [[ExportName]]: *exportName* } to resolveSet. - 4\. If SameValue(*exportName*, "default") is true, then - - a\. Return the HTML Document associated with this HTML Module record. - - b\. NOTE: I assume here that we’re not trying to pass through default exports of the inline scripts. + - a\. Return ResolvedBinding Record { [[Module]]: *module*, [[BindingName]]: *\*default\** } + - b\. NOTE 1: *\*default\** was set up to reference the HTML Module's document during instantiation/execution + - c\. NOTE 2: I assume here that we’re not trying to pass through default exports of the inline scripts. - 5\. Let *starResolution* be null. - 6\. For each ScriptEntry record *se* in *module*.[[RequestedModules]], do: - a\. If *se*.[[InlineModuleRecord]] == null, continue to next record. @@ -105,19 +115,18 @@ These spec changes are built on top of the proposed refactoring here: https://gi - 8\. Set *htmlModule’s* *record* to *result*. - 9\. Return *htmlModule*. - Provide an implementation of the abstract operation HostParseHTMLModule(*source*, *realm*, *htmlModule*) as the following. - - 1\. Let *record* be a new HTML Module Record that this algorithm will subsequently initialize. - - 2\. Run the HTML5 parser on *source* to obtain the result *document*. - - 3\. Set *record*.[[HostDefined]] = *htmlModule*. - - 4\. For each HTMLScriptElement *script* in *document*: - - a\. Let *se* be a new ScriptEntry record (see definition in ES6 changes above). + - 1\. Run the HTML5 parser on *source* to obtain the result *document*. + - 2\. Let *scriptEntries* be an empty list of ScriptEntry Records (see definition in ES6 changes above). + - 3\. For each HTMLScriptElement *script* in *document*: + - a\. Let *se* be a new ScriptEntry record. - b\. If *script* is inline: - i\. Set *se*[[InlineModuleRecord]] = *script’s* Source Text Module Record - ii\. Set *se*[[ExternalScriptURL]] = null - c\. Else - i\. Set *se*[[InlineModuleRecord]] = null - ii\. Set *se*[[ExternalScriptURL]] = *script’s* src URL - - d\. Append *se* to *record*.[[RequestedModules]] - - 5\. Return *record*. + - d\. Append *se* to *scriptEntries*. + - 4\. Return a new HTML Module Record { [[Realm]]: *realm*, [[Environment]]: *undefined*, [[Namespace]]: *undefined*, [[Status]]: `"uninstantiated"`, [[EvaluationError]]: *undefined*, [[HostDefined]]: *document*, [[RequestedModules]]: *scriptEntries*, [[DFSIndex]]: *undefined*, [[DFSAncestorIndex]]: *undefined* }. - Change [fetch a single module script](https://html.spec.whatwg.org/#fetch-a-single-module-script) as follows: - In step 9, allow `text/html` type through in addition to JavaScript. - In step 11, don’t unconditionally [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). Instead, key off the MIME type extracted in step 9, creating an HTML Module instead if we have a `text/html` MIME type. From a3e6ff1f0483f0bcf1271ddbb509465dbb5ceac2 Mon Sep 17 00:00:00 2001 From: Daniel Clark Date: Tue, 12 Feb 2019 16:02:45 -0800 Subject: [PATCH 3/6] Add plumbing for ES spec to get the HTML Module's default export (the document) and set it to the *document* binding during module Evaluation. Plus some other minor corrections. --- proposals/html-module-spec-changes.md | 92 +++++++++++++++------------ 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/proposals/html-module-spec-changes.md b/proposals/html-module-spec-changes.md index bc4eb8e9..834de6b5 100644 --- a/proposals/html-module-spec-changes.md +++ b/proposals/html-module-spec-changes.md @@ -8,15 +8,15 @@ Questions/corrections/feedback are welcome! I've left TODOs in several places w These spec changes are built on top of the proposed refactoring here: https://github.com/tc39/ecma262/pull/1311 -- Introduce a new subtype of Cyclic Module Record in addition to the existing [Source Text Module Record](https://tc39.github.io/ecma262/#sourctextmodule-record), named HTML Module Record. - 1. HTML Module Records reuse the [[RequestedModules]] field of Cyclic Module Record, but instead of a list of strings it is a list of ScriptEntry records. See definition of HostParseHTMLModule in HTML5 spec changes for a specification of how these are populated. +- Introduce a new subtype of Cyclic Module Record (TODO Add link to Cyclic MR once it's part of the official spec) in addition to the existing [Source Text Module Record](https://tc39.github.io/ecma262/#sourctextmodule-record), named HTML Module Record. + 1. HTML Module Records reuse the [[RequestedModules]] field of Cyclic Module Record, but instead of a list of strings it is a list of ScriptEntry records. See definition of ParseHTMLModule in HTML5 spec changes for a specification of how these are populated (although it is important to note that ES has no knowledge of this process which involves the HTML Parser, inline vs external script elements etc). _[TODO: This reuse-name-with-different-type is pretty fishy. Should [[RequestedModules]] in Cyclic MR be generalized as a list that can hold objects of a type specified in each subclass? Or should we use an entirely new field in HTML MR? Or should we generate unique IDs for the inline script elements and place them in the Module Map, so that an HTML Module Record can just use strings in [[RequestedModules]]?]._ ScriptEntry is defined as: | Field Name | Value Type | Meaning | | --- | --- | --- | - | [[InlineModuleRecord]] | Module Record \| null | The Source Text Module Record for the module request if it was avaiable at parse time. Null otherwise. | - | [[ExternalScriptURL]] | String \| null | The URL for the module request if the Module Record was not available at parse time. Null otherwise. | + | [[InlineModuleRecord]] | Module Record \| null | The Module Record for the module request. May be set when the module is created, or initially Null and set later during module Instantiation. | + | [[ExternalScriptURL]] | String \| null | The URL for the module request if the Module Record was not available at module creation time. Null otherwise. | 2. The [[HostDefined]] field in Abstract Module Record will be set to the HTML Module Script (see HTML5 Spec changes). This is analogous to script modules where this field holds the JavaScript [module script](https://html.spec.whatwg.org/multipage/webappapis.html#module-script) as defined in the HTML5 spec. - HTML Module Record inherits the concrete Instantiate() method from Cyclic Module Record. - HTML Module Record defines its own version of [InnerModuleInstantiation](https://tc39.github.io/ecma262/#sec-innermoduleinstantiation). Cyclic Module Record's definition recursively calls InnerModuleInstantiation on each child module (calling [HostResolveImportedModule](https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule) to resolve module names to Module Records), then calls [ModuleDeclarationEnvironmentSetup](https://tc39.github.io/ecma262/#sec-moduledeclarationenvironmentsetup) to set up the lexical environment and resolve imports/exports for the current module. HTML Module Record's version will be similar, but will change the definition of step 9 (“For each string required that is an element of module.[[RequestedModules]]...) in order to follow the structure of the newly defined ScriptEntry record as defined above. @@ -30,19 +30,24 @@ These spec changes are built on top of the proposed refactoring here: https://gi - e\. Assert: *requiredModule*.[[Status]] is either "instantiating", "instantiated", or "evaluated". - f\. Assert: *requiredModule*.[[Status]] is "instantiating" if and only if *requiredModule* is in *stack*. - g\. If *requiredModule*.[[Status]] is "instantiating", then - - i\. Assert: *requiredModule* is a Source Text Module Record. - - ii\. Set *module*.[[DFSAncestorIndex]] to min(*module*.[[DFSAncestorIndex]], *requiredModule*.[[DFSAncestorIndex]]). + - i\. Set *module*.[[DFSAncestorIndex]] to min(*module*.[[DFSAncestorIndex]], *requiredModule*.[[DFSAncestorIndex]]). - HTML Module Record provides a concrete implementation of InitializeEnvironment(), implementing the corresponding abstract method on Cyclic Module Record. This function is responsible for creating a mutable binding with the name "*default*" that will be used to set up the HTML Module's document as the module's default export. 1. Let _module_ be this HTML Module Record. 1. Let _realm_ be _module_.[[Realm]]. 1. Assert: _realm_ is not *undefined*. 1. Let _env_ be NewModuleEnvironment(_realm_.[[GlobalEnv]]). - 1. Set _module_.[[Environment]] to _env_. 1. Let _envRec_ be _env_'s EnvironmentRecord. + 1. Set _module_.[[Environment]] to _env_. + 1. Let _envRec_ be _env_'s EnvironmentRecord. 1. Perform ! _envRec_.CreateMutableBinding("\*default\*", *false*). TODO Should this be CreateImmutableBinding? 1. Call _envRec_.InitializeBinding("\*default\*", *undefined*). - 1. Return NormalCompletion(~empty~). - -- HTML Module Record provides a concrete implementation of ExecuteModule(), implementing the corresponding abstract method on Cyclic Module Record. The implementation is just a no-op. The Source Text Module Record version of this method initializes the execution context of the module and executes its code, but HTML modules have no code of their own to execute so there is nothing to do. + 1. Return NormalCompletion(empty). +- Declare an implementation-defined abstract operation HostGetDefaultExport(_module_) whose purpose is to return the value of *module*'s default export, or null if there isn't one. +- HTML Module Record provides a concrete implementation of ExecuteModule(), implementing the corresponding abstract method on Cyclic Module Record. For HTML modules there is no script to execute. This method just sets up the HTML Module's default export, obtained from the implementation-defined HostGetDefaultExport. + 1. _module_ be this HTML Module Record. + 1. Let _defaultExport_ be HostGetDefaultExport(_module_). + 1. Let _envRec_ be _module_.[[Environment]]'s EnvironmentRecord. + 1. Call _envRec_.SetMutableBinding("\*default\*", _defaultExport_, *false*). + 1. Return NormalCompletion(empty). - HTML Module Record should implement a modified version of [GetExportedNames](https://tc39.github.io/ecma262/#sec-getexportednames)(*exportStarSet*), as follows: - 1\. Let *module* be this HTML Module Record. - 2\. If *exportStarSet* contains *module*, then @@ -65,30 +70,29 @@ These spec changes are built on top of the proposed refactoring here: https://gi - i\. Assert: This is a circular import request. - ii\. Return null. - 3\. Append the Record { [[Module]]: *module*, [[ExportName]]: *exportName* } to resolveSet. - - 4\. If SameValue(*exportName*, "default") is true, then - - a\. Return ResolvedBinding Record { [[Module]]: *module*, [[BindingName]]: *\*default\** } - - b\. NOTE 1: *\*default\** was set up to reference the HTML Module's document during instantiation/execution - - c\. NOTE 2: I assume here that we’re not trying to pass through default exports of the inline scripts. - - 5\. Let *starResolution* be null. - - 6\. For each ScriptEntry record *se* in *module*.[[RequestedModules]], do: - - a\. If *se*.[[InlineModuleRecord]] == null, continue to next record. + - 4\. Let *resolution* be null. + - 5\. For each ScriptEntry record *se* in *module*.[[RequestedModules]], do: + - a\. If *se*.[[ExternalScriptURL]] != null, continue to next record. - b\. Let *importedModule* be *se*.[[InlineModuleRecord]]). - - c\. Let *resolution* be ? importedModule.ResolveExport(*exportName*, *resolveSet*). - - d\. If *resolution* is "**ambiguous**", return "**ambiguous**". - - e\. If *resolution* is not null, then - - i\. Assert: *resolution* is a ResolvedBinding Record. - - ii\. If *starResolution* is null, set *starResolution* to *resolution*. + - c\. Let *singleResolution* be ? *importedModule*.ResolveExport(*exportName*, *resolveSet*). + - d\. If *singleResolution* is "**ambiguous**", return "**ambiguous**". + - e\. If *singleResolution* is not null, then + - i\. Assert: *singleResolution* is a ResolvedBinding Record. + - ii\. If *resolution* is null, set *resolution* to *singleResolution*. - iii\. Else, - a\. Assert: There is more than one inline script that exports the requested name. - b\. Return "**ambiguous**". - - 7\. Return *starResolution*. + - 6\. If *resolution* is null and SameValue(*exportName*, "default") is true, then + - a\. Let *resolution* be a ResolvedBinding Record { [[Module]]: *module*, [[BindingName]]: *\*default\** } + - b\. NOTE 1: *\*default\** was set up to reference the HTML Module's document during instantiation/execution + - c\. NOTE 2: I assume here that we’re not trying to pass through default exports of the inline scripts. + - 7\. Return *resolution*. - HTML Module Record inherits the concrete Evaluate() method from Cyclic Module Record. -- HTML Module Record should implement a modified version of [InnerModuleEvaluation](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script)(*module*, *stack*, *index*). This method calls InnerModuleEvaluation on each child module, then executes the current module. The HTML Module version will have the following changes: - - Change step 10 and step 10a to be the following, to account for the different structure of HTML Module Record vs Source Text Module Record. Steps 10b-10f remain the same: +- HTML Module Record should implement a modified version of Cyclic Module Record's [InnerModuleEvaluation](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script)(*module*, *stack*, *index*). This method calls InnerModuleEvaluation on each child module, then executes the current module. The HTML Module version will have the following changes (TODO Make sure these step numbers are still correct after Cyclic Module Record is merged into the official spec): + - Change step 10 and step 10a to be the following, to account for the different structure of HTML Module Record vs Cyclic Module Record. Steps 10b-10f remain the same: - 10\. For each ScriptEntry *se* in *module*.[[RequestedModules]]), do: - a\. If (*se*.[[InlineModuleRecord]] != null), let *requiredModule* be *se*.[[InlineModuleRecord]], else let *requiredModule* be HostResolveImportedModule(*module*, *se*.[[ExternalScriptURL]]) - - Omit step 11 (since the HTML module doesn’t have any JS code of its own to run; it only recurses to run the code of its requested modules per step 10). - - Declare an implementation-defined abstract operation HostParseHTMLModule(*source*, *realm*, *htmlModule*). This operation will create an instance of HTML Module Record and populate its fields. See HTML5 spec changes below for the concrete implementation. +- Note that we don't define any operation in ES for creation of HTML Module Records. This is implemented entirely in HTML5 (see spec changes below). # HTML5 spec changes ([full spec link](https://html.spec.whatwg.org/)): - Introduce a third type of [script](https://html.spec.whatwg.org/multipage/webappapis.html#concept-script) named HTML Module Script. It has the following item in addition to script: @@ -100,22 +104,23 @@ These spec changes are built on top of the proposed refactoring here: https://gi - Rename [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script) to "create a JavaScript module script". - Introduce a new algorithm “create an HTML module script”, similar to [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). The definition would look something like this: - To create an HTML module script, given a JavaScript string *source*, an environment settings object *settings*, a URL *baseURL*, and some script fetch options *options*: - - 1\. Let *htmlModule* be a new HTML module script that this algorithm will subsequently initialize. - - 2\. Set *htmlModule’s* settings object to *settings*. - - 3\. Set *htmlModule’s* *base URL* to *baseURL*. - - 4\. Set *htmlModule’s* fetch options to *options*. - - 5\. Set *htmlModule's* *parse error* and *error to rethrow* to null. - - 6\. Let *result* be ParseHTMLModule(*source*, *settings's* Realm, *htmlModule*). Note: Passing *htmlModule* as the last parameter here ensures *result*.[[HostDefined]] will be *htmlModule*. See below bullet for ParseHTMLModule definition. - - 7\. For each ScriptEntry *required* of *result*.[[RequestedModules]], such that *required*[[InlineModuleRecord]] == null: - - a\. Let *url* be the result of resolving a module specifier given *htmlModule’s* *base URL* and *required*[[ExternalScriptURL]]. + - 1\. Let *htmlModuleScript* be a new HTML module script that this algorithm will subsequently initialize. + - 2\. Set *htmlModuleScript*'s settings object to *settings*. + - 3\. Set *htmlModuleScript*'s *base URL* to *baseURL*. + - 4\. Set *htmlModuleScript*'s fetch options to *options*. + - 5\. Set *htmlModuleScript*'s *parse error* and *error to rethrow* to null. + - 6\. Let *result* be ParseHTMLModule(*source*, *settings's* Realm, *htmlModuleScript*). Note: Passing *htmlModuleScript* as the last parameter here ensures *result*.[[HostDefined]] will be *htmlModuleScript*. See below bullet for ParseHTMLModule definition. + - 7\. For each ScriptEntry *required* of *result*.[[RequestedModules]], such that *required*[[InlineModuleRecord]] == null: + - a\. Let *url* be the result of resolving a module specifier given *htmlModuleScript*'s *base URL* and *required*[[ExternalScriptURL]]. - b\. If *url* is failure, then: - i\. Let *error* be a new TypeError exception. - - ii\. Set *htmlModule’s* *parse error* to *error*. - - iii\. Return *htmlModule*. Note: This step is essentially validating all of the requested module specifiers. We treat a module with unresolvable module specifiers the same as one that cannot be parsed; in both cases, a syntactic issue makes it impossible to ever contemplate instantiating the module later. - - 8\. Set *htmlModule’s* *record* to *result*. - - 9\. Return *htmlModule*. -- Provide an implementation of the abstract operation HostParseHTMLModule(*source*, *realm*, *htmlModule*) as the following. + - ii\. Set *htmlModuleScript*'s *parse error* to *error*. + - iii\. Return *htmlModuleScript*'s. Note: This step is essentially validating all of the requested module specifiers. We treat a module with unresolvable module specifiers the same as one that cannot be parsed; in both cases, a syntactic issue makes it impossible to ever contemplate instantiating the module later. + - 8\. Set *htmlModuleScript*'s *record* to *result*. + - 9\. Return *htmlModuleScript*. +- Introduce a new algorithm ParseHTMLModule(*source*, *realm*, *htmlModuleScript*) as the following. - 1\. Run the HTML5 parser on *source* to obtain the result *document*. + - 2\. Set *htmlModuleScript*[[document]] to *document* - 2\. Let *scriptEntries* be an empty list of ScriptEntry Records (see definition in ES6 changes above). - 3\. For each HTMLScriptElement *script* in *document*: - a\. Let *se* be a new ScriptEntry record. @@ -126,7 +131,12 @@ These spec changes are built on top of the proposed refactoring here: https://gi - i\. Set *se*[[InlineModuleRecord]] = null - ii\. Set *se*[[ExternalScriptURL]] = *script’s* src URL - d\. Append *se* to *scriptEntries*. - - 4\. Return a new HTML Module Record { [[Realm]]: *realm*, [[Environment]]: *undefined*, [[Namespace]]: *undefined*, [[Status]]: `"uninstantiated"`, [[EvaluationError]]: *undefined*, [[HostDefined]]: *document*, [[RequestedModules]]: *scriptEntries*, [[DFSIndex]]: *undefined*, [[DFSAncestorIndex]]: *undefined* }. + - 4\. Return a new HTML Module Record { [[Realm]]: *realm*, [[Environment]]: *undefined*, [[Namespace]]: *undefined*, [[Status]]: `"uninstantiated"`, [[EvaluationError]]: *undefined*, [[HostDefined]]: *htmlModuleScript*, [[RequestedModules]]: *scriptEntries*, [[DFSIndex]]: *undefined*, [[DFSAncestorIndex]]: *undefined* }. +- Provide an implementation of the abstract operation HostGetDefaultExport(*module*) as the following: + 1. Assert: *module* is an HTML Module. Note: It is anticipated that in the future this may be expanded to support other module types (JSON etc). + 1. Let *htmlModuleScript* be *module*.[[HostDefined]]. + 1. Let *document* be *htmlModuleScript*'s *document*. + 1. Return *document*. - Change [fetch a single module script](https://html.spec.whatwg.org/#fetch-a-single-module-script) as follows: - In step 9, allow `text/html` type through in addition to JavaScript. - In step 11, don’t unconditionally [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). Instead, key off the MIME type extracted in step 9, creating an HTML Module instead if we have a `text/html` MIME type. From 60ad86607d79b00cdb1574175c5198bb12d8813c Mon Sep 17 00:00:00 2001 From: Daniel Clark Date: Tue, 12 Feb 2019 16:29:00 -0800 Subject: [PATCH 4/6] Update proposal to state that non-module scripts in HTML Module will cause error (rather than being silently coerced to type='module' --- proposals/html-modules-proposal.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/html-modules-proposal.md b/proposals/html-modules-proposal.md index 8663b825..6b916b66 100644 --- a/proposals/html-modules-proposal.md +++ b/proposals/html-modules-proposal.md @@ -42,7 +42,7 @@ Example: > ``` **Solution:** -We propose that all scripts in HTML Modules are automatically module scripts regardless of *type* attribute. ES6 Modules don't pollute the global scope, as only explicitly exported variables are accessible. +If when parsing an HTML Module a script without `type="module"` is encountered, this will be considered a parse error that causes creation of the module to fail. Thus, an HTML Module can contain only module scripts. ES6 Modules don't pollute the global scope, as only explicitly exported variables are accessible. #### 2. Parse blocking with inline script @@ -70,7 +70,7 @@ Example: **Solution:** -This is also addressed by our proposal for [item 1](#1-global-object-pollution): make all scripts in HTML Modules automatically module scripts regardless of type attribute. ES6 Modules have defer semantics and thus don't block the parser. +This is also addressed by our proposal for [item 1](#1-global-object-pollution): limit HTML Modules to contain `type="module"` scripts only. ES6 Modules have defer semantics and thus don't block the parser. #### 3. Inability for script modules to access declarative content @@ -130,7 +130,7 @@ Merge the HTML Imports loading system into the existing ES6 Modules system. The current system for building a dependency graph of HTML Imports as specified in https://www.w3.org/TR/html-imports/ will need to be changed. Instead, each imported HTML Module will have its own module record as introduced in the ES6 spec and will participate in the ES6 Module map and Module dependency graphs. Like a script module today has a [Source Text Module Record](https://tc39.github.io/ecma262/#sec-source-text-module-records), we will introduce a new subclass of the [Abstract Module Record](https://tc39.github.io/ecma262/#sec-abstract-module-records) type (perhaps "HTML Module Record"). Where a Source Text Module Record contains the script for the module ([[ECMAScriptCode]]), an HTML Module record would contain the import document object, along with its own [[RequstedModules]] list, imports/exports, etc. As module scripts in the HTML Module are encountered during parse time, they will be added to the HTML Module record's [[RequestedModules]] list, ensuring that they are instantiated/executed prior to their HTML Module's instantiation/execution and that they can export content to be exposed through the HTML Module's record, as explained in [item 5](#5-non-intuitive-import-pass-through) below. -This merge is greatly simplified by our proposed solution to [item 1](#1-global-object-pollution): since we treat all scripts in HTML Modules as type="module" and all module scripts have defer semantics, we don't have synchronous script elements causing side-effects during parsing. This allows us to resolve the entire import graph before executing any script -- which is a key aspect of the ES6 Modules system. +This merge is greatly simplified by our proposed solution to [item 1](#1-global-object-pollution): since HTML Modules can only contain module scripts and all module scripts have defer semantics, we don't have synchronous script elements causing side-effects during parsing. This allows us to resolve the entire import graph before executing any script -- which is a key aspect of the ES6 Modules system. #### 5. Non-intuitive import pass through From efb952cde5631863bc36230bbbc586f175b4f3f7 Mon Sep 17 00:00:00 2001 From: Daniel Clark Date: Wed, 13 Feb 2019 10:50:45 -0800 Subject: [PATCH 5/6] Minor wording/typo fixes. Eliminate disclaimer at the top about some parts being handwavy -- we've mostly progressed beyond that, I think. --- proposals/html-module-spec-changes.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/proposals/html-module-spec-changes.md b/proposals/html-module-spec-changes.md index 834de6b5..52f75ca4 100644 --- a/proposals/html-module-spec-changes.md +++ b/proposals/html-module-spec-changes.md @@ -1,4 +1,4 @@ -This is a list of spec areas that will need to be changed to implement our [HTML Modules proposal](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/html-modules-proposal.md). Some of the proposed changes are very specific and some are more handwavy depending on how deep I've investigated into that particular area. +This is a list of spec areas that will need to be changed to implement our [HTML Modules proposal](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/html-modules-proposal.md) Questions/corrections/feedback are welcome! I've left TODOs in several places where we still have open questions; any input regarding these is especially appreciated. -- [@dandclark](https://github.com/dandclark), with:\ @@ -15,8 +15,8 @@ These spec changes are built on top of the proposed refactoring here: https://gi | Field Name | Value Type | Meaning | | --- | --- | --- | - | [[InlineModuleRecord]] | Module Record \| null | The Module Record for the module request. May be set when the module is created, or initially Null and set later during module Instantiation. | - | [[ExternalScriptURL]] | String \| null | The URL for the module request if the Module Record was not available at module creation time. Null otherwise. | + | [[InlineModuleRecord]] | Module Record \| null | The Module Record for the module request if available at ScriptEntry creation time. Null otherwise. | + | [[ExternalScriptURL]] | String \| null | The URL for the module request if the Module Record was not available at ScriptEntry creation time. Null otherwise. | 2. The [[HostDefined]] field in Abstract Module Record will be set to the HTML Module Script (see HTML5 Spec changes). This is analogous to script modules where this field holds the JavaScript [module script](https://html.spec.whatwg.org/multipage/webappapis.html#module-script) as defined in the HTML5 spec. - HTML Module Record inherits the concrete Instantiate() method from Cyclic Module Record. - HTML Module Record defines its own version of [InnerModuleInstantiation](https://tc39.github.io/ecma262/#sec-innermoduleinstantiation). Cyclic Module Record's definition recursively calls InnerModuleInstantiation on each child module (calling [HostResolveImportedModule](https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule) to resolve module names to Module Records), then calls [ModuleDeclarationEnvironmentSetup](https://tc39.github.io/ecma262/#sec-moduledeclarationenvironmentsetup) to set up the lexical environment and resolve imports/exports for the current module. HTML Module Record's version will be similar, but will change the definition of step 9 (“For each string required that is an element of module.[[RequestedModules]]...) in order to follow the structure of the newly defined ScriptEntry record as defined above. @@ -31,17 +31,18 @@ These spec changes are built on top of the proposed refactoring here: https://gi - f\. Assert: *requiredModule*.[[Status]] is "instantiating" if and only if *requiredModule* is in *stack*. - g\. If *requiredModule*.[[Status]] is "instantiating", then - i\. Set *module*.[[DFSAncestorIndex]] to min(*module*.[[DFSAncestorIndex]], *requiredModule*.[[DFSAncestorIndex]]). -- HTML Module Record provides a concrete implementation of InitializeEnvironment(), implementing the corresponding abstract method on Cyclic Module Record. This function is responsible for creating a mutable binding with the name "*default*" that will be used to set up the HTML Module's document as the module's default export. +- HTML Module Record provides a concrete implementation of InitializeEnvironment(), implementing the corresponding abstract method on Cyclic Module Record. This function is responsible for creating a mutable binding with the name "\*default\*" that will be used to set up the HTML Module's document as the module's default export. 1. Let _module_ be this HTML Module Record. 1. Let _realm_ be _module_.[[Realm]]. 1. Assert: _realm_ is not *undefined*. 1. Let _env_ be NewModuleEnvironment(_realm_.[[GlobalEnv]]). 1. Set _module_.[[Environment]] to _env_. 1. Let _envRec_ be _env_'s EnvironmentRecord. - 1. Perform ! _envRec_.CreateMutableBinding("\*default\*", *false*). TODO Should this be CreateImmutableBinding? + 1. Perform ! _envRec_.CreateMutableBinding("\*default\*", *false*). 1. Call _envRec_.InitializeBinding("\*default\*", *undefined*). 1. Return NormalCompletion(empty). - Declare an implementation-defined abstract operation HostGetDefaultExport(_module_) whose purpose is to return the value of *module*'s default export, or null if there isn't one. + - Note: See HTML5 spec changes below for the implementation. - HTML Module Record provides a concrete implementation of ExecuteModule(), implementing the corresponding abstract method on Cyclic Module Record. For HTML modules there is no script to execute. This method just sets up the HTML Module's default export, obtained from the implementation-defined HostGetDefaultExport. 1. _module_ be this HTML Module Record. 1. Let _defaultExport_ be HostGetDefaultExport(_module_). @@ -115,7 +116,7 @@ These spec changes are built on top of the proposed refactoring here: https://gi - b\. If *url* is failure, then: - i\. Let *error* be a new TypeError exception. - ii\. Set *htmlModuleScript*'s *parse error* to *error*. - - iii\. Return *htmlModuleScript*'s. Note: This step is essentially validating all of the requested module specifiers. We treat a module with unresolvable module specifiers the same as one that cannot be parsed; in both cases, a syntactic issue makes it impossible to ever contemplate instantiating the module later. + - iii\. Return *htmlModuleScript*. Note: This step is essentially validating all of the requested module specifiers. We treat a module with unresolvable module specifiers the same as one that cannot be parsed; in both cases, a syntactic issue makes it impossible to ever contemplate instantiating the module later. - 8\. Set *htmlModuleScript*'s *record* to *result*. - 9\. Return *htmlModuleScript*. - Introduce a new algorithm ParseHTMLModule(*source*, *realm*, *htmlModuleScript*) as the following. @@ -139,7 +140,7 @@ These spec changes are built on top of the proposed refactoring here: https://gi 1. Return *document*. - Change [fetch a single module script](https://html.spec.whatwg.org/#fetch-a-single-module-script) as follows: - In step 9, allow `text/html` type through in addition to JavaScript. - - In step 11, don’t unconditionally [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). Instead, key off the MIME type extracted in step 9, creating an HTML Module instead if we have a `text/html` MIME type. + - In step 11, don’t unconditionally [create a module script](https://html.spec.whatwg.org/#fetching-scripts:creating-a-module-script). Instead, key off the MIME type extracted in step 9, using the “create an HTML module script” steps instead if we have a `text/html` MIME type. - Replace step 5 of [fetch the descendants of a module script](https://html.spec.whatwg.org/#fetch-the-descendants-of-a-module-script) with the following steps: - 5\. If *module script* is a JavaScript module script, then: - 1\. [For each](https://infra.spec.whatwg.org/#list-iterate) string *requested* of *record*.[[RequestedModules]], From 67f0c473b917feeb9e544d85c035eab7fd08c645 Mon Sep 17 00:00:00 2001 From: Daniel Clark Date: Thu, 14 Feb 2019 10:53:38 -0800 Subject: [PATCH 6/6] Add note that parser behavior needs further specification. Change 'fetch a single module script' section to reflect that HTML Modules MIME type discussion is still ongoing. --- proposals/html-module-spec-changes.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/proposals/html-module-spec-changes.md b/proposals/html-module-spec-changes.md index 52f75ca4..bd119b78 100644 --- a/proposals/html-module-spec-changes.md +++ b/proposals/html-module-spec-changes.md @@ -121,6 +121,7 @@ These spec changes are built on top of the proposed refactoring here: https://gi - 9\. Return *htmlModuleScript*. - Introduce a new algorithm ParseHTMLModule(*source*, *realm*, *htmlModuleScript*) as the following. - 1\. Run the HTML5 parser on *source* to obtain the result *document*. + - a\. TODO: This needs to be fleshed out more. Do we need to run the parser in a special mode to ensure that nothing is fetched and no script runs? Script execution should already be [disabled because the HTML Module document does not have a browsing context](https://html.spec.whatwg.org/#concept-n-noscript), but the case for fetching is less clear. We also need to specify the special handling for non-module `