The stage 3 Import Assertions proposal puts forward the following syntax to allow certain attributes to be passed into the module loader.
// static imports
import config from "./config.json" assert { type: "json" };
// dynamic imports
const config = await import("./config.json", { assert: { type: "json" } })
The original goal of this proposal was to enable non-JavaScript module types (e.g., JSON and CSS). Feedback from browsers was that such module types should be driven by syntax at the import site. The initial strategy was to generalize this to arbitrary syntax for annotating import statements. Subsequently, it was narrowed to only provide for assertions, based on an understanding that this met all of the needs for specifying the module type being imported.
However, browsers have subsequently found that the module type will need to play a role in the fetching of modules. This behavior disagrees with the specification’s requirements and the conceptual idea of the type being asserted rather than driving the interpretation of the module, which makes assert
the wrong keyword for this proposal.
As a strawperson we can consider identifying the module type and other qualities with a general “import attribute” syntax:
import config from "./config" with type: "json";
This syntax should be understood to mean that the qualities which follow with
may affect the interpretation of the module, in line with both web integration requirements and ordinary developer intuition (we’ve found it very difficult to convince anyone that import assertions are not what drives the interpretation of the module).
An alternative, which we disprefer, is to continue using the assert
syntax, with the understanding that web browsers may violate the semantic requirements of the JavaScript specification, that import assertions behave as assertions.
We prefer to maintain alignment between multiple layers of specifications, as well as alignment with developer intuition. If the semantics will no longer be assertion-based, we’d prefer to change the syntax, if we can manage the pain that the near-term churn would cause.
If we do adopt a more general “import attributes” option in place of import assertions, this would have additional benefits for two other proposals which which also seek to modify the syntax of import declarations: stage 2 Import Reflection and stage 1 Deferred Imports. This suggests an opportunity for a general-purpose way of specifying import attributes that can not only cover module type specifications, but also these two proposals and possible future ones, of which there could potentially be many. The already complex syntax of import statements risks becoming untenably complicated unless we provide an extensible outlet. What follows is just one possible way that one of those proposals could piggyback on the present proposal:
import x from "y" with type: "json", reflect: "module";
Previously, TC39 delegates raised significant concerns about import attributes being too flexible, leading to a risk of ecosystem divergence–that there would be a lot of different ways to give meaning to these attributes, and different environments would make mismatching choices (e.g., putting certain kinds of configuration inline, when it should be in a separate configuration file), limiting the portability and intelligibility of code. This is why we adopted the limitation to “import assertions” between Stage 2 and 3. Further, if we do want to indicate things like module reflection and deferred evaluation through import attributes, the situation could become difficult if ecosystem code also defines keys in the same namespace.
To mitigate these risks, we could consider possible limitations on import attributes, e.g.,
- The
type
is the only attribute which can affect how the module is fetched and interpreted. (That is, it is the only part which is a key of the module map.) - All non-
type
attributes are defined by TC39, and none by the rest of the ecosystem. They are all about how the module is made available to JS, and not how it is fetched and interpreted. (That is, they are not a key of the module map.)
As with syntax, we don’t have a strong conclusion to draw yet, however.
The immediate goal of this presentation is to signal to implementers that the champions intend to take the somewhat unusual step of proposing late revisions to these proposals, and to request implementers to delay any current plans they may have of shipping these proposals in their current state.
If revision of the proposal is ever going to happen it must happen very quickly, as some browsers and tools have already shipped import assertions, and others have complete implementations behind a flag. This document does not propose what specific changes should be made to the import assertion proposals, only that we allow time for iteration on this proposal to meet newly discovered requirements. We will aim to draw a conclusion on this topic in the following March 2022 TC39 meeting.
Given the alternatives being discussed and the divergence issue, I recommend we revert the proposal back to stage 2 and request implementations to disable the feature.