# Import Maps 101

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:

```javascript
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](https://github.com/iamkun/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:

```html
<!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.

```javascript
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](https://cdn.hashnode.com/res/hashnode/image/upload/v1660360834972/jzv1DwuK1.png align="center")

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

```html
<!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](https://cdn.hashnode.com/res/hashnode/image/upload/v1661427306177/pwxY30131.gif align="center")

### 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`.

```javascript
<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](https://marketplace.visualstudio.com/items?itemName=JSPM.jspm-vscode).

## 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](https://github.com/WICG/import-maps).

## 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1660912708001/zSUuqz1He.png align="center")

## Polyfills

If you want import maps to be supported in any browser, there is an [ES Module Shims](https://github.com/guybedford/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:

```html
<!-- 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](https://github.com/guybedford/es-module-shims)

## 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

* https://github.com/WICG/import-maps
    
* https://wicg.github.io/import-maps/
    
* https://github.com/guybedford/es-module-shims
    
* https://caniuse.com/import-maps
    
* https://marketplace.visualstudio.com/items?itemName=JSPM.jspm-vscode
