[Proposal] HTML Modules


#1

With ES6 Script Modules, there is currently no good way to access declarative HTML content from a module. For example, if I’m defining a custom element in a script module, how do I set up the element’s shadow tree? Currently I’d be required to build it though means like setting an innerHTML string or constructing it bit-by-bit with document.createElement()/appendChild() etc. Ideally though, I’d like to just write HTML and get access to it from my script module, in a way that the HTML and the script module can be bundled together.

My colleagues on the Microsoft Edge team and I have developed a proposal for HTML Modules, an extension of ES6 Script Modules that allows for access to declarative HTML content from within a script module. With HTML Modules, one can simply import the DOM content from an HTML file using the existing ES6 Module syntax: import {element} from "./myElement.html";

Please see our explainer doc with the details.

Any feedback is appreciated!

There was previous discussion of this proposal on this GitHub issue thread and at TPAC 2018.


#2

In order for script in an HTML Module to access the module’s own HTML content, we introduce a new import.meta.document property that refers to the HTML Module document. We limit this to inline module scripts only

Am I right that pages using a CSP must then allow ‘unsafe-inline’ for scripts for this to work? If so I am skeptical of specifying features that require relaxing security restrictions to use.

As an MVP, why not only support importing plain HTML documents? i.e. only this feature:

import importedDoc from "import.html"

Why would anyone prefer to write an inline script using import.meta.document to just writing that code using importedDoc beneath the import?

Why would anyone prefer to import more scripts through a HTML module than just importing from the JS module?

Why would anyone prefer to export things from a HTML module than just exporting from the JS module?

If you only support importing the document, you can do everything using the existing JS infrastructure - and it would considerably simplify the feature.


#3

While we could do a MVP of content-only imports, many of the scenarios we read about that used HTML Imports wanted to have some opportunities for custom setup or processing that would require script execution–the feature seemed a little too limited without allowing any script to run.

Also, there’s the aspect of packaging all the content together–since HTML is a natural carrier of inline CSS and JavaScript, it makes sense to be able to bring all that content together.

I’m not sure about whether ‘unsafe-inline’ is needed for HTML modules. I suppose your preference is to not need to use unsafe-inline. Since inline scripts in HTML modules aren’t actually run ‘in-line’ then perhaps they don’t apply?


#4

An MVP could easily be extended in future to cover things like inline scripts, import.meta.document etc. Shipping an MVP would not close off any of these options. On the other hand shipping the full-blown feature will make it very hard to backtrack in future if it turns out to be the wrong direction, due to backwards compatibility concerns. So I think the value of shipping an MVP is to reduce the risk that we get this wrong again. It already happened to HTML imports, which are currently in the long and difficult process of being phased out. So I think it would be wise to take this one step at a time.

the feature seemed a little too limited without allowing any script to run

This doesn’t prevent using script at all. Basically anything you could do by importing a HTML module with an inline script, you can also do by importing a script module that itself imports a HTML module. This is pretty much transparent to the importer, it just means things are shuffled around internally.

I’m not sure about whether ‘unsafe-inline’ is needed for HTML modules.

I think we should get a clear answer on this before proceeding. I don’t feel I know enough about this to say for sure either way.


#5

Thanks AshleyScirra for raising the point about unsafe-inline. After discussed discussing this and other CSP considerations at some length with other Edge folks I’ve posted our thoughts so far as a new issue on the WebAppSec working group. Feedback or confirmation from the experts there should help inform us on how to proceed.


#6

We’re excited to see this proposal moving forward; many thanks for everyone’s work on this.

Overall, this seems like the general shape of the modules proposal would fit our needs nicely. We only have minor comments, mostly related to the way the Explainer’s examples portray what you may expect to be common usage.

  1. Is it necessary to wrap the module contents in <html> and <body>? (The html5Element.html example shows this, but the inline examples in the Explainer do not.) I’d believe it if you said html and body were necessary, but the inline Explainer examples without those elements seem so much cleaner.

  2. There’s no reason to define a <head>, is there?

  3. The HTML5Element example would encourage people to define a custom element registration function, when it seems simpler and more flexible to just export the element class. The class can then be used in lots of ways, e.g., registered via custom element registries someday.


#7

Hi Jan,

You’re right that the HTML5Element example can be simplified. There’s no need to specify <html>, <body>, or <head>; the HTML5 parser will inject these automatically per normal HTML5 parsing rules. I also like the idea of exporting the custom element class directly.

I updated our example to follow all these points. Thanks for the feedback!


#8

Thanks for the support folks! We’re intending to open a new repo for HTML modules in the WICG github organization shortly, where we’ll have a dedicated issue tracker to continue the discussion as this feature incubates.


#9

I just noticed the repo was created here.


#10

Yeah, I created the repo but didn’t want to announce it before it gets populated.