Import Maps 101

Import Maps 101

Enhancing the developer experience for importing libraries

As web developers, the use of external libraries has saved us a lot of time and effort, allowing us to build apps faster and more efficiently. In this article, I will be introducing you to a spec called import maps to control the behaviour of importing these libraries.

Introduction

Typically, using external libraries in browsers requires bundlers/build tools such as webpack or browserify in order to parse the code and allow the use of import statements. These are known as bare modules. Modules which are imported without an absolute or relative URL cannot be imported in the browser without bundle tools.

For example, importing the lodash package would be written as:

import _ from "lodash";

This bare import specifier makes it easier to write and manage code, without having to write absolute/relative URLs of the library.

What exactly does Import Maps solve?

With bundlers and build tools solving the issue with bare imports, you may now wonder what problem import maps actually solves.

The short answer is: import maps can be used to load bare modules without the need for bundlers.

The longer explanation is that normally, code gets bundles altogether into a large file import maps can be used to control the behaviour of importing libraries, such as when it is needed at runtime, remapping of URL-like specifiers, scoping, dynamic imports, etc. This allows better caching for module script graphs and better developing performance.

Example Usage

Let's take a look at an example implementation of import maps. In this tutorial, we will learn how to import a bare module like dayjs without the use of a bundler.

Step 1: Create index.html and index.js

First, let's create a new HTML page index.html and script called index.js.

In our index.html, let's import index.js as a module like so:

<!DOCTYPE html>
<html lang="en-US">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Import Maps Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script type="module" src="./index.js"></script>
</head>

<body>
</body>

</html>

Step 2: Write a simple script in index.js

Now let's write something simple that uses dayjs. For this example, I am writing a script that prints out the current datetime every second.

import dayjs from "dayjs";

const el = document.createElement("h1");

document.body.appendChild(el);

setInterval(() => {
  el.innerHTML = dayjs(Date.now()).format("YYYY-MM-DD HH:mm:ss");
}, 1000);

Step 3: Add import maps to import the library

If you try running the page now, it obviously would not work because the dayjs we imported in index.js is a bare module. You will see the following error:

error.png

So let's use import maps to resolve this error. Back in index.html add the following:

<!DOCTYPE html>
<html lang="en-US">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Import Maps Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Add this importmap before index.js -->
    <script type="importmap">
        {
          "imports": {
            "dayjs": "https://cdn.skypack.dev/dayjs@1.11.5"
          }
        }
      </script>
    <script type="module" src="./index.js"></script>
</head>

<body>
</body>

</html>

Note: When implementing import maps, ensure that it is added before the first module load is started, in this example, index.js.

Now let's run the page and our script should be running with no issues.

result.gif

Scopes

Another important aspect to know about import maps is scoping, which allows the use of multiple versions of the same package in a specified scope.

For example, the code below specifies that any module in /src path will use the https://cdn.skypack.dev/dayjs@1.10.7 package, while anything outside that path will use https://cdn.skypack.dev/dayjs@1.11.5.

<script type="importmap">
        {
          "imports": {
            "dayjs": "https://cdn.skypack.dev/dayjs@1.11.5"
          },
          "scopes": {
            "/src": {
              "dayjs": "https://cdn.skypack.dev/dayjs@1.10.7"
            }
          }
        }
  </script>
`

This is useful in the case where you need to work with multiple versions of the same package simultaneously for various reasons such as compatibility with other libraries, ensuring legacy systems can still run and so on.

VS Code Extension

Alternatively, instead of writing our import maps script, there is a VS Code extension which can automatically generates and injects import maps for modules and HTML pages.

You can learn more about this extension here.

Other Usages

There are also many other uses of import maps besides allowing bare module imports such as:

  • Importing modules within modules
  • Allow extension-less imports
  • Remapping imports (mapping away hashes)

You may learn more about these useful features in the official documentation.

Browser Support

In terms of browser support, at the time of this article (Aug 2022), it is supported in Chromium-based browsers only (i.e. Chrome, Edge).

More of this information can be found in the image below:

image.png

Polyfills

If you want import maps to be supported in any browser, there is an ES Module Shims polyfill which is compatible with any browser that has baseline ES Module Support (i.e. Edge 17+, Firefox 60+, Safari 10.1+, and Chrome 61+).

To use it, simply add the polyfill script with an async attribute and add an import map or module script below:

<!-- import polyfill here -->
<script async src="https://ga.jspm.io/npm:es-module-shims@1.5.16/dist/es-module-shims.js"></script>

<script type="importmap">
{
  "imports": {
    "react": "https://ga.jspm.io/npm:react@18.0.0-rc.0/index.js"
  },
  "scopes": {
    "https://ga.jspm.io/npm:react@18.0.0-rc.0/": {
      "object-assign": "https://ga.jspm.io/npm:object-assign@4.1.1/index.js"
    }
  }
}
</script>

<script type="module">
  import react from 'react';
  console.log(react);
</script>

Example code taken from here

Conclusion

In this article, we learned about import maps, what problems it can solve and how to implement it. Thanks for reading, I hope it has been a helpful article in getting you started with import maps.

Please read more about it in the References section below. Leave a like and share this article if it is insightful! Cheers!

References

Did you find this article valuable?

Support Victoria Lo by becoming a sponsor. Any amount is appreciated!

ย