ECMAScript proposal: Import assertions

[2021-01-11] dev, javascript, es proposal
(Ad, please don’t block)

The ECMAScript proposal “Import assertions” (by Myles Borins, Sven Sauleau, Dan Clark, and Daniel Ehrenberg) introduces syntax for associating metadata with import statements. In this blog post, we examine what that looks like and why it’s useful.

Import assertions  

The motivating use case for import assertions was importing JSON data as a module. That looks as follows (and is further specified in a separate proposal):

import config from './data/config.json' assert { type: 'json' };

You may wonder why a JavaScript engine can’t use the filename extension .json to determine that this is JSON data. However, a core architectural principle of the web is to never use the filename extension to determine what’s inside a file. Instead, content types are used.

Therefore, there is a risk of doing importing wrong if a server has incorrectly configured content types. Specifying the necessary metadata at the import location solves this issue.

Before we take a more detailed look at how import assertions work, let’s examine the history of importing non-JavaScript artifacts in the world of JavaScript.

History: importing non-JavaScript artifacts as modules  

Importing artifacts that are not JavaScript code as modules, has a long tradition in the JavaScript ecosystem.

For example, the JavaScript module loader RequireJS has support for so-called plugins. To give you a feeling for how old RequireJS is: Version 1.0.0 was released in 2009. Specifiers of modules that are imported via a plugin look like this:

'«specifier-of-plugin-module»!«specifier-of-artifact»'

For example, the following module specifier imports a file as JSON:

'json!./data/config.json'

Inspired by RequireJS, webpack supports the same module specifier syntax for its loaders.

Use cases for importing non-JavaScript artifacts  

These are a few use cases for importing non-JavaScript artifacts:

  • Importing JSON configuration data
  • Importing WebAssembly code as if it were a JavaScript module
  • Importing CSS to build user interfaces

For more use cases, you can take a look at the list of webpack’s loaders.

The syntax of import assertions  

Let’s examine in more detail what import assertions look like.

Static import statements  

We have already seen a normal (static) import statement:

import config from './data/config.json' assert { type: 'json' };

The import assertions start with the keyword assert. That keyword is followed by an object literal. For now, the following object literal features are supported:

  • Unquoted keys and quoted keys
  • The values must be strings

There are no other syntactic restrictions placed on the keys and the values, but engines are encouraged to throw an exception if they don’t support a key and/or a value. That makes it easier to add more features in the future because no one will use keys and values in unexpected ways.

Dynamic imports  

To support import assertions, dynamic imports get a second parameter – an object with configuration data:

import('./data/config.json', { assert: { type: 'json' } })

The import assertions don’t exist at the top level; they are specified via the property assert. That makes it possible to add more configuration options in the future.

Re-export statements  

A re-export imports and exports in a single step. For the former, we need assertions:

export { default as config } from './data/config.json' assert { type: 'json' };

Upcoming features based on import assertions  

Import assertions are really just syntax. They lay the foundation for actual features that make use of that syntax.

JSON modules  

The first feature based on import assertions is probably going to be JSON modules.

Importing WebAssembly  

Whether or not import assertions will be used to support directly importing WebAssembly from JavaScript is currently under discussion. If they are used, we’ll probably be able to create web workers like this:

new Worker('my-app.wasm', { type: 'module', assert: { type: 'webassembly' } })

And we’d also need import assertions in HTML script elements:

<script src="my-app.wasm" type="module" asserttype="webassembly"></script>

Further reading on modules  

The chapter on “Modules” in “JavaScript for impatient programmers” is an in-depth introduction to ECMAScript modules.