Problems with import assertions for module types …
… and a solution!
+ downgrade to Stage 2
Nicolò Ribaudo
January 2023
Outline
2
Recap: what are import assertions?
import styles from "./main.css" assert { type: "css" };
let stylesP = import("./main.css", { assert: { type: "css" } });
The assertion can check that the imported module respects some conditions, and throw an error (preventing its evaluation) if it doesn't.
3
Host invariants on import assertions handling
4
Host invariants on import assertions handling
5
Host invariants on import assertions handling
If all imports succeed, A === B and B === C should be true.
6
const A = await import("./x");
const B = await import("./x", { assert: { type: "json" } });
const C = await import("./x", { assert: { type: "yaml" } });
History!
import json from "./foo.json" with type: "json";
import json from "./foo.json" as "json";
import json from "./foo.json" assert { type: "json" };
7
Resource types on the web
8
Resource types on the web
Resources on the web are loaded differently depending on their usage goal, and they are differentiated before knowing what the server response contains.
9
Resource types on the web
<link rel="stylesheet" href="/file">
GET /file HTTP/1.1
...
Accept: text/css,*/*;q=0.1
Sec-Fetch-Dest: style
...
<script type="module" src="/file">
</script>
GET /file HTTP/1.1
...
Accept: */*
Sec-Fetch-Dest: script
...
10
Resource types on the web
import "/file" assert { type:"css" }
GET /file HTTP/1.1
...
Accept: text/css,*/*;q=0.1
Sec-Fetch-Dest: style
...
import "/file";
GET /file HTTP/1.1
...
Accept: */*
Sec-Fetch-Dest: script
...
11
Can the browser fetch these two modules as if they were loaded using the corresponding <link> and <script> tags?
Developers' mental model of import assertions
12
What causes a module do be interpreted in a certain way?
There is a strong developer intuition that the type assertion guides the engine to interpret the module according to the specified type.
In current implementations, type 1-1 matches the MIME type or file extension of the imported module, and it's either required (e.g. JSON modules) or disallowed (JS modules). It's not observably false that it doesn't affect how the module is interpreted.
13
import data from "/data.json" assert { type:"json" }
Real-world attempts to overload assertions semantics
14
A possible solution
15
A possible solution
import styles from "./styles.css" with { type: "css" };
* the syntax is a strawperson heavily based on the existing assert-only�syntax, and with was one of the alternative keywords originally�considered for this feature before settling on assert-only semantics.
16
Possible further benefits
There are currently other proposals planning to extend the import syntax:
With a generic "attributes" syntax, we can simply define new attributes instead of inventing new syntax every time:
17
Limiting ecosystem divergence
Previously, significant concerns were raised about import attributes being too flexible, limiting portability and intelligibility of code.
Possible compromise
18
Expressiveness
A previous alternative that only extended the import syntax with a simple string was deemed as being too restrictive and preventing future extensions:
import styles from "./style.css" as "css";
This proposal currently defines a single type: string attribute, but it has a clear extension path:
import "./style.css" with { optional: true, allow: ["fs-read"] }
19
Web compatibility & migration path
20
Web compatibility & migration path
Import assertions have not been enabled everywhere yet! However, they are already enabled in some browsers, server-side runtimes and tools.
Now No immediate action to take. It's fine to not unship the current implementation.
In background Collect statistics on how frequently import assertions are used.
In a few months If we get consensus on new semantics, implementations can ship them and use the same code path for the assert syntax.
Mid/long-term Analyze the impact of removing assert from existing implementation. Hopefully it can be done in one year or two.
21
Next steps
22
Next steps
import x from "y" with { type: "css" };
import x from "y" with type: "css";
import x from "y" as "css";
import x from "y" as <any primitive literal>;
23
Downgrade to Stage 2?
24