sajad torkamani

What are import maps?

Import maps is a proposal that provides control over what URLs get fetched by JavaScript import statements. The basic idea is that you can ship modular JavaScript like the below directly to the browser without transpiling it through a tool like Webpack:

import moment from "moment";
import { partition } from "lodash";

For this to work, you supply the browser with an importmap like this:

<script type="importmap">
{
  "imports": {
    "moment": "/node_modules/moment/src/moment.js",
    "lodash": "/node_modules/lodash-es/lodash.js"
  }
}
</script>

which would essentially translate to:

import moment from "/node_modules/moment/src/moment.js";
import { partition } from "/node_modules/lodash-es/lodash.js";

Import maps = no Webpack = Win!

Even better, you can avoid NPM and Node.js altogether by supplying HTTP paths instead:

<script type="importmap">
{
  "imports": {
    "moment": "https://ga.jspm.io/npm:moment.js",
    "lodash": "https://ga.jspm.io/npm:lodash"
  }
}
</script>

Is it safe to use?

There’s native support for import maps in Chrome / Edge 89+. There’s also a shim for browsers with basic ESM support so that it should work for around 95% of users.

Import maps in Rails

How to install

importmap-rails is included by default in Rails 7+ applications.

For older Rails apps, you can do:

  1. Run ./bin/bundle add importmap-rails
  2. Run ./bin/rails importmap:install

Configuration

The import map is configured in config/importmap.rb and will look something like this in a fresh Rails 7 project:

# frozen_string_literal: true

# Pin npm packages by running ./bin/importmap

pin 'application', preload: true
pin '@hotwired/turbo-rails', to: 'turbo.min.js', preload: true
pin '@hotwired/stimulus', to: 'stimulus.min.js', preload: true
pin '@hotwired/stimulus-loading', to: 'stimulus-loading.js', preload: true
pin_all_from 'app/javascript/controllers', under: 'controllers'

This import map is then included in the app/views/layouts/application.html.erb via <%= javascript_importmap_tags %>. You can view the output in your browser’s devtools.

Add to importmap via CDN

You can use the ./bin/importmap pin command to get Rails to resolve NPM packages via the jspm.org CDN. For example, suppose you want to pin alpinejs, you can run:

./bin/importmap pin alpinejs

and Rails will append the following to your config/importmap.rb:

pin 'alpinejs', to: 'https://ga.jspm.io/npm:alpinejs@3.8.1/dist/module.esm.js'

Add to importmap via /vendor directory

If you don’t want to use a CDN, you can download vendored files from the CDN instead:

./bin/importmap pin alpinejs --download

This will output something like:

Pinning "alpinejs" to vendor/javascript/alpinejs.js via download from https://ga.jspm.io/npm:alpinejs@3.9.5/dist/module.esm.js

You can then use the download vendor/javascript/<package> in your application.

View importmap

You can use the ./bin/importmap json command to view your importmap:

./bin/importmap json

{
  "imports": {
    "application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js",
    "@hotwired/turbo-rails": "/assets/turbo.min-96cbf52c71021ba210235aaeec4720012d2c1df7d2dab3770cfa49eea3bb09da.js",
    "@hotwired/stimulus": "/assets/stimulus.min-900648768bd96f3faeba359cf33c1bd01ca424ca4d2d05f36a5d8345112ae93c.js",
    "@hotwired/stimulus-loading": "/assets/stimulus-loading-685d40a0b68f785d3cdbab1c0f3575320497462e335c4a63b8de40a355d883c0.js",
    "alpinejs": "https://ga.jspm.io/npm:alpinejs@3.8.1/dist/module.esm.js",
    "controllers/application": "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js",
    "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
    "controllers": "/assets/controllers/index-2db729dddcc5b979110e98de4b6720f83f91a123172e87281d5a58410fc43806.js"
  }
}

Remove from importmap

./bin/importmap unpin alpinejs

Sources

Tagged: Rails