Intent to Implement: HTML Modules

3,858 views
Skip to first unread message

Daniel Clark

unread,
Jan 16, 2019, 10:20:31 PM1/16/19
to blin...@chromium.org, Sam Sebree, Travis Leithead, Bo Cupp

Contact emails

dan...@microsoft.comsase...@microsoft.comtra...@microsoft.compc...@microsoft.com

Explainer

HTML Modules Explainer

Design Doc/Spec

HTML Modules Design Doc

HTML Modules Proposed Spec Changes

TAG Review (in progress)

Summary

We are proposing an extension of the ES6 Script Modules system to include HTML Modules. These will allow web developers to package and access declarative content from script in a way that allows for good componentization and reusability, and integrates well into the existing ES6 Modules infrastructure.

Motivation

The introduction of ES6 Script Modules has provided several benefits for javascript developers including more componentized code and better dependency management. However, easy access to declarative content has been a consistent limitation with Script Modules. For example, if one wants to pack a custom element definition in a module, how should the HTML for the element's shadow tree be created? Current solutions would involve generating it dynamically (document.createElement or innerHTML), but it would be preferable to simply write HTML and include it with the module. With HTML Modules this will be possible.

There is clear demand for this functionality in the developer community -- see this thread where ideas pertaining to HTML Modules have resulted in a great deal of developer and browser implementer engagement.

HTML Imports were proposed (and implemented in Chromium) as a solution, but they were developed independently of ES6 Modules and have several limitations:

  • Global object pollution: vars created in an HTML Import show up on the global object by default. An ideal solution would minimize such side-effects. Accordingly, global object pollution does not occur in ES6 Modules.
  • Parse blocking with inline script: the load of an HTML Import will block the main document's parser if included prior to an inline script element. ES6 Modules have defer semantics and thus do not block the parser.
  • Independent of dependency resolution infrastructures between HTML Imports and HTML Modules: since these systems were developed independently their infrastructures for dependency resolution don't talk to each other, leading to missed performance opportunities and to bugs like this one.
  • Non-intuitive import pass through: HTML Imports requre the consumer to access their content due to standard DOM queries like getElementById and querySelector. This is clumsy and limited relative to Script Modules' import/export statements that allow for explicit specification of the API surface provided by a module.

Integrating HTML Modules into the existing ES6 Module system, rather than creating it as a standalone component, will address these gaps.

Risks

Interoperability and Compatibility

Interoperability risk:

We plan to initially ship the feature behind a runtime flag so that developers can experiment with the concept while spec changes are still being finalized.

Other browser implementers have expressed their support of the concept and its exploration during a Web Platform WG meeting at TPAC 2018 (see meeting minutes here). Specifically:

  • Edge: We're strongly in favor of the feature. Given the newly shared engine, Edge's support will arrive in a similar timeframe to Chromium.
  • Firefox: Expressed support at TPAC 2018. See also this response to our initial proposal and this page summarizing Mozilla's stance on HTML Imports and the status update it links to that indicates their desire to pursue a solution better aligned with ES modules.
  • Safari: Expressed support at TPAC 2018.
  • Web / Framework developers: The responses to this post include a good cross-section of developer sentiment (mostly positive with some expressing concern about various details of the proposal), e.g. [1], [2], [3].
  • See alsoGoogle presentation at BlinkOn about the idea of HTML Modules as a replacement for HTML Imports.

Compatibility risk:

Same as Interoperability risk

Ergonomics

HTML Modules are expected to be used in tandem with Script Modules. They will share the existing import/export syntax, and both types of modules can be imported from the other.

Performance will be pay-for-play. Performance of Script Modules that don't use HTML Modules will not be affected; the only added cost would be various "is this an HTML or a Script Module" checks. There will be no impact outside of the module infrastructure.

Activation

Developers already familiar with ES6 Script Modules should find HTML Modules easy to pick up, as they introduce no changes to the existing import/export changes and are a logical extension of the current system. Areas that may present some initial difficulty are the use of inline Script Modules to define the exports of an HTML Module, and the fact that non-module scripts are not allowed in an HTML Module. We will need to ensure that this behavior is well-documented and that the errors emitted by DevTools are clear and helpful. Beyond these basic concepts though there is nothing that introduces significant complexity beyond that of existing ES6 Module behavior.

Debuggability

The debugging experience will be similar to that of ES6 Script Modules as it is today. Developers will be able to view the source files for HTML Modules in the DevTools Sources tab, and will be inline script in these files will support the same level as debugging as inline script in normal files (setting breakpoints, stepping through and inspecting vars, etc).

HTML Module documents and the elements they contain will be dumpable in the DevTools console tab like normal DOM content.

Will this feature be supported on all six Blink platforms (Windows, Mac, Linux, Chrome OS, Android, and Android WebView)?

Yes, this feature will be platform agnostic.

Is this feature fully tested by web-platform-tests?

Not yet, but we are working on a full set of tests that will be upstreamed to the web-platform-tests-suite.

Link to entry on the feature dashboard

TBD

Requesting approval to ship?

No

 

Yutaka Hirano

unread,
Jan 17, 2019, 12:28:24 AM1/17/19
to Daniel Clark, blin...@chromium.org, Sam Sebree, Travis Leithead, Bo Cupp
Hi,

I skimmed the design document, and was surprised by "CORS error" in the following code. Can you tell me why CORS is involved here?

if (mime_type == "text/html") {
  // Create HTMLModule
} else if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type)) {
  // Create ScriptModule
} else {
  // Emit CORS error and refuse to create a module.
}
Thanks,

--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/blink-dev/MW2PR2101MB113022D6F7A6903E890E45E0C5820%40MW2PR2101MB1130.namprd21.prod.outlook.com.

Daniel Clark

unread,
Jan 17, 2019, 12:21:33 PM1/17/19
to Yutaka Hirano, blin...@chromium.org, Sam Sebree, Travis Leithead, Bo Cupp

Hi Yutaka,

 

Good catch, this is just a typo.  This error should be about MIME-type checking rather than CORS.  The comment should really be “Emit an error that the file failed strict MIME type checking; ‘text/html’ or a JavaScript MIME-type is required” or something along those lines.

 

I’ll correct the document.

 

Thanks!

-- Dan

Yutaka Hirano

unread,
Jan 17, 2019, 8:02:53 PM1/17/19
to Daniel Clark, blin...@chromium.org, Sam Sebree, Travis Leithead, Bo Cupp
Thank you!

Jochen Eisinger

unread,
Jan 28, 2019, 3:36:35 AM1/28/19
to Yutaka Hirano, ne...@google.com, Daniel Clark, blin...@chromium.org, Sam Sebree, Travis Leithead, Bo Cupp
+Georg Neis who works on ES6 modules to check the integration with HTML modules

ne...@google.com

unread,
Feb 6, 2019, 3:07:11 PM2/6/19
to blink-dev, Sam.S...@microsoft.com, travis....@microsoft.com, pc...@microsoft.com, Jochen Eisinger, Kouhei Ueno, Adam Klein, Hiroshige Hayashizaki, Domenic Denicola, Takayoshi Kochi
I've had a look ​mainly ​at the ES-related bits and they look reasonable to me.​ A few comments below.​ I'm also CC'ing some other folks who might have feedback on this proposal.


​Concerning ES​:

- ​You need to define the Instantiate and Evaluate methods. They, in contrast to InnerModuleInstantiate and InnerModuleEvaluate, are part of the interface of abstract module records.

​- Related to that, it's not good enough if the HTML InnerModuleInstantiation calls the STMR (Source Text Module Record) InnerModuleInstantiation on its inline modules. You also need to change the STMR InnerModuleInstantiation such that it calls ​the HTML InnerModuleInstantiation on any HTML module. Currently, it simply calls Instantiate on anything that's not an STMR, which means that cycles involving both STMR and HTML won't work.

- In the context of Webassembly, there's an effort to allow cycles between non-STMR and STMR by essentially moving the cycle-tracking machinery into the interface of abstract module records: https://github.com/tc39/ecma262/pull/1311
I'm not familiar with the exact details, but I assume that your proposal would look a little more natural in that setting.

- ​Regarding the result of ResolveExport for the "default" binding, you already observed that simply returning the document object doesn't make sense because a ResolvedBinding is expected. I suggest that you return a ResolvedBinding consisting of the module and the binding name "*default*" (just like for STMR) and then create an environment for your module that maps "*default*" to the document object.

- The assertion at the top of GetExportedNames should talk about HTML Module Record.


​Concerning ​HTML​:​

- "We propose that all scripts in HTML Modules are automatically module scripts regardless of type attribute"

In order to avoid confusion, wouldn't it be safer to ​forbid classic script​s​ ​(scripts without type=module)​ inside of an HTML module?


​Concerning ​V8​:​

- "The module_record for this HTMLModuleScriptEntry will be filled in later during module graph instantiation."
Is this important, or merely a micro-optimization because one can always obtain the module via the resolve-callback?

​- "​Note that these are added to Module rather than HTMLModule (and all existing fields on Module will remain there) because V8 HeapObjects' don't appear to have an established pattern for splitting up data members between super- and sub-types.​"

I don't see any issue with adding them only to HTMLModule. Could you elaborate?​


​Best,
Georg​
--
Georg Neis
Software Engineer

Google Germany GmbH
Erika-Mann-Straße 33
80636 München

Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg

Diese E-Mail ist vertraulich. Falls sie diese fälschlicherweise erhalten haben sollten, leiten Sie diese bitte nicht an jemand anderes weiter, löschen Sie alle Kopien und Anhänge davon und lassen Sie mich bitte wissen, dass die E-Mail an die falsche Person gesendet wurde.

This e-mail is confidential. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it has gone to the wrong person.

dan...@microsoft.com

unread,
Feb 15, 2019, 5:18:18 PM2/15/19
to blink-dev, Sam.S...@microsoft.com, travis....@microsoft.com, pc...@microsoft.com, eisi...@google.com, kou...@google.com, ad...@google.com, hiro...@google.com, dom...@google.com, ko...@google.com

Hi Georg,

 

Thanks for your detailed feedback!  I’ve made the following changes to the proposed spec changes doc in response to your comments:

  • Rebased the ES changes on https://github.com/tc39/ecma262/pull/1311.  The most obvious change here is that HTML Module Record is now a subclass of Cyclic Module Record.
    • The changes for this should also address your second point about cycles involving both STMR and HTMLMR not working.
  • HTML MR now inherits the concrete implementations of Instantiate() and Evaluate() from Cyclic MR (HTML MR still defines its own InnerModuleInstantiation /InnerModuleEvaluation.
  • Updated ResolveExport to return a ResolvedBinding rather than the document itself.  HTML MR implementations of InitializeEnvironment() and ExecuteModule() were added to create a binding named “*default*” and set it to the document.
  • Corrected GetExportedNames to refer to HTML MR instead of Source Text MR.

 

I’ve also made some changes in response to feedback elsewhere:

  • HTML Module on the HTML5 side is now a type of Script called HTML Module Script, and the existing Module Script is renamed to JavaScript Module Script.
  • ScriptEntry’s [[ScriptName]] field is renamed to [[ExternalScriptURL]] and [[ModuleRecord]] is renamed to [[InlineModuleRecord]].  The [[IsInline]] field was removed.
  • Fixed ResolveExport so that it the HTML Module’s default export doesn’t override a default export specified by an inline script.
  • Updated and refactored “create a module script” and ParseHTMLModule to ensure that all fields are initialized for HTML Module Script and HTML Module Record creation.

 

There are still some questions around whether the bulk of HTML Module Record and its algorithms should actually be defined in the HTML5 spec.  I expect this document to continue to evolve.

 

Regarding your other comments:

 

I agree that coercing non-module scripts to type=”module” in HTML Module documents could be confusing.  We’ve gotten this feedback elsewhere as well.  I’ve updated the docs to state that a non-module script in an HTML Module document will be treated as a parse error that causes the HTML Module Record to fail to be created.

 

  • > "The module_record for this HTMLModuleScriptEntry will be filled in later during module graph instantiation."
    > Is this important, or merely a micro-optimization because one can always obtain the module via the resolve-callback?

This is just a micro-optimization in the proposed V8 implementation.  It’s similar to how things are already being done with Script Modules in V8, where the resolve-callback is used only during module Instantiation and the results are stashed so that the resolve-callback is not used again during module Evaluation.

 

  • ​> "​Note that these are added to Module rather than HTMLModule (and all existing fields on Module will remain there) because V8 HeapObjects' don't appear to have an established pattern for splitting up data members between super- and sub-types.​"
    > I don't see any issue with adding them only to HTMLModule. Could you elaborate?​

My statement here was just incorrect, I had a misunderstanding about HeapObject layout in V8.  I’ve removed it from the doc.

 

Thank you for taking the time to review the documents!

 

-- Dan

rek...@gmail.com

unread,
Aug 1, 2019, 8:14:12 PM8/1/19
to blink-dev, Sam.S...@microsoft.com, travis....@microsoft.com, pc...@microsoft.com, eisi...@google.com, kou...@google.com, ad...@google.com, hiro...@google.com, dom...@google.com, ko...@google.com
Hello Microsoft, pardon the late reply:

Is there any where to track this feature's implementation? I don't see any tickets linked in the original post. I would love to see something to track.

If I don't hear back, I can open an issue. I did search the bug tracker but didn't find anything. At the moment I have to keep scanning the entire internet to see if I find anything like news on this topic, and having something concrete to look in at would be a great help. Thanks.

Arvind Murching

unread,
Aug 2, 2019, 1:06:21 AM8/2/19
to blink-dev, Sam.S...@microsoft.com, travis....@microsoft.com, pc...@microsoft.com, eisi...@google.com, kou...@google.com, ad...@google.com, hiro...@google.com, dom...@google.com, ko...@google.com

Joe Medley

unread,
Aug 2, 2019, 2:29:31 PM8/2/19
to Arvind Murching, blink-dev, Sam.S...@microsoft.com, Travis Leithead, pc...@microsoft.com, Jochen Eisinger, Kouhei Ueno, Adam Klein, Hiroshige Hayashizaki, Domenic Denicola, Takayoshi Kochi
This needs a Chrome Status entry too. I've given you access. Login is at the bottom. After logging in, look for the "Add new feature" button at the top.
Joe Medley | Technical Writer, Chrome DevRel | jme...@google.com | 816-678-7195
If an API's not documented it doesn't exist.


--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

tra...@microsoft.com

unread,
Aug 5, 2019, 7:20:24 PM8/5/19
to blink-dev, arv...@microsoft.com, Sam.S...@microsoft.com, travis....@microsoft.com, pc...@microsoft.com, eisi...@google.com, kou...@google.com, ad...@google.com, hiro...@google.com, dom...@google.com, ko...@google.com
Entry created: https://chromestatus.com/features/4854408103854080. Thanks for the reminder!


On Friday, August 2, 2019 at 11:29:31 AM UTC-7, Joe Medley wrote:
This needs a Chrome Status entry too. I've given you access. Login is at the bottom. After logging in, look for the "Add new feature" button at the top.
Joe Medley | Technical Writer, Chrome DevRel | jme...@google.com | 816-678-7195
If an API's not documented it doesn't exist.


On Thu, Aug 1, 2019 at 10:06 PM 'Arvind Murching' via blink-dev <blin...@chromium.org> wrote:
Arvind

On Thursday, August 1, 2019 at 5:14:12 PM UTC-7, rek...@gmail.com wrote:
Hello Microsoft, pardon the late reply:

Is there any where to track this feature's implementation? I don't see any tickets linked in the original post. I would love to see something to track.

If I don't hear back, I can open an issue. I did search the bug tracker but didn't find anything. At the moment I have to keep scanning the entire internet to see if I find anything like news on this topic, and having something concrete to look in at would be a great help. Thanks.

--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blin...@chromium.org.
Reply all
Reply to author
Forward
0 new messages