Skip to content

Instantly share code, notes, and snippets.

@peetklecha
Last active January 20, 2023 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peetklecha/a55532165dbd4905aa91bbe59e8b1001 to your computer and use it in GitHub Desktop.
Save peetklecha/a55532165dbd4905aa91bbe59e8b1001 to your computer and use it in GitHub Desktop.
Problems with import assertions for module types and a possible general solution

Import Attributes

History

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.

The problem

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.

Possible remedies

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.

Further possible benefits of import attributes

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";

Limiting ecosystem divergence

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.

Immediate next steps

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.

@msaboff
Copy link

msaboff commented Jan 19, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment