1 of 27

ES Module Attributes

For Stage 2

Myles Borins, Google

Daniel Ehrenberg, Igalia in partnership with Bloomberg

Sven Sauleau, Babel

Daniel Clark, Microsoft

2 of 27

For Stage 2

3 of 27

Spec

https://tc39.es/proposal-module-attributes

Complete first draft; mechanics fully specified

4 of 27

Babel parser implementation

5 of 27

webpack experiment

https://github.com/xtuc/module-attributes

6 of 27

Core design decisions

for Stage 2

7 of 27

Define the interpretation of attributes across host environments

Some will be defined by ECMA-262: `type`

type: "json" => single default export: output of JSON.parse

Specify more attributes and types over time, both TC39 and hosts

The host is responsible for handling module attributes

https://github.com/tc39/proposal-module-attributes/issues/10, https://github.com/tc39/proposal-module-attributes/issues/16

8 of 27

Invariants required of all hosts for module attributes

type must be interpreted as a check, not a command to reinterpret a module (i.e., not part of the cache key)

type: "json" must be a module consisting of a single default export which is the result of JSON.parse on some string

(Open to guaranteeing more invariants before Stage 3)

9 of 27

Impact on the host module hooks

(Open to editorial revisions, through Stage 4)

HostResolveImportedModule and HostImportModuleDynamicallytook String "specifier" argument

Now take a ModuleRequest record

10 of 27

Don’t use module specifier to pass attributes

import json from "import+json://./foo.json";

Not very human friendly

Various existing interpretations of module specifiers

Unclear how to unify cross-environment behavior

May lead to security issues

https://github.com/tc39/proposal-module-attributes/issues/11

11 of 27

Using a general key-value syntax (as opposed to single string)

import a from "b" with keya: "1", keyb: “2”, ... ;

More uses-case and future proof

Better compatibility across env, avoids passing all in one string

Currently only String Literals

https://github.com/tc39/proposal-module-attributes/issues/12

12 of 27

Module attributes are inline in the import

Inline: import json from "./foo.json" with type: "json";

Straightforward editing; tab-completes well

No switching between files to add/change an import

Tooling friendly

https://github.com/tc39/proposal-module-attributes/issues/13

13 of 27

Out of band format for module types?

Yet another configuration file to manage, including:

  • Tools to generate/combine/distribute/serve/package/parse
  • Poor manual authoring/maintenance experience

Analogous cross environment issues to in-band

This proposal does not rule out other out-of-bound proposals

We probably want out-of-band for, e.g., integrity hashes

https://github.com/tc39/proposal-module-attributes/issues/13

14 of 27

Well-understood decision points we're comfortable revisiting after Stage 2, before Stage 3

15 of 27

Question: should JSON module be frozen?

Current proposal: a normal object, just like JSON.parse outputs

Idea: use a frozen object instead

Champion group's take: Open to this change, but sticking with the mutable "default" for now; most consistent with rest of universe

https://github.com/tc39/proposal-module-attributes/issues/54

16 of 27

Question: type: “javascript”

If no type is specified, it must be possible to have a JS module

Should we add a type to redundantly express this, for some kind of consistency?

Champion group's take: Open to adding, but don't see the need

https://github.com/tc39/proposal-module-attributes/issues/49

17 of 27

Question: detailed semantics on the Web

Basics: Request the module, check that the MIME type matches the type in module attributes, then parse/interpret the modules

Open question: Send a header to the server based on the type?

To answer in WHATWG as part of HTML spec,�draft prepared before Stage 3

https://github.com/tc39/proposal-module-attributes/issues/29, https://github.com/tc39/proposal-module-attributes/issues/7

18 of 27

Question: Add { } around module attributes?

import a from "b" with { keya: "1", keyb: “2”, ... };

More similar to object literals--may be good or bad

Non-core bikeshed

Champion group's take: No brackets seems fine; open to changing

https://github.com/tc39/proposal-module-attributes/issues/5

19 of 27

Question: change “with” keyword?

import a from "b" with keya: "1", keyb: “2”, ...;

import a from "b" as keya: "1", keyb: “2”, ...;

import a from "b" if keya: "1", keyb: “2”, ...;

For, having, given, etc.

Another non-core bikeshed

Champion group's take: with seems good to us, open to changing�

https://github.com/tc39/proposal-module-attributes/issues/3

20 of 27

Further host invariants

In the current draft, hosts have lots of flexibility:

  • Hosts may ignore or reject unknown attributes
  • Hosts may reject imports of the same specifier with mismatching attributes, or make a separate copy interpreted differently
  • Hosts may expose attributes in import.meta, but not guaranteed

Before Stage 3, open to making more specific requirements on hosts

Base investigation on details of concrete hosts and attributes

https://github.com/tc39/proposal-module-attributes/issues/64

21 of 27

Stage2?

22 of 27

Revisiting based on feedback: Additional constraints on hosts

Bonus reprise

23 of 27

Host ability to clone modules due to attributes

  • Previously: Hosts may reject imports of the same specifier with mismatching attributes, or make a separate copy interpreted differently

New proposal

  • Hosts must not clone modules due to attributes, or use module attributes to affect how a module is interpreted, just to perform checks
    • Open to revisiting in the future (during Stage 2 and in follow-on proposals)

https://github.com/tc39/proposal-module-attributes/pull/66

24 of 27

25 of 27

26 of 27

s/module attributes/� import attributes/g��???

https://github.com/tc39/proposal-module-attributes/issues/65

27 of 27

Stage2?