---
title: Upgrade your Rails app from esbuild to import-maps
url: https://sxnlabs.com/en/ruby/2023/11/10/upgrade-rails-from-to-esbuild-to-import-maps/
lang: en
date: '2023-11-10T11:00:00+02:00'
tags:
- Javascript
- Ruby on Rails
---

# Upgrade your Rails app from esbuild to import-maps

The [import-maps](https://github.com/rails/importmap-rails) gem finally allows us to get rid of JavaScript tooling in our Ruby on Rails projects, whether it's esbuild or webpacker.

Let's see together how to convert a project using esbuild, in my case, to import-maps.

## Initial State

Our layout links the `application.js` and `application.css` files.

```erb
# views/layouts/application.html.erb
<head>
  <!-- ... -->
  <%%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  <%%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
</head>
```

The CSS file imports styles from various NPM packages located in the `node_modules` directory as well as [TailwindCSS](https://tailwindcss.com) directives.

```css
@import "notyf/notyf.min";
@import "trix/dist/trix";
@import "actiontext.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
```

And the JS file imports different packages as well as our [Stimulus](https://stimulus.hotwired.dev) controllers.

```js
import "@hotwired/turbo-rails";
import "trix";
import "@rails/actiontext";
import "./controllers";
```

A setup that couldn't be more classic.

## Installing `import-map`

If your app wasn't created with Rails 7+, run the commands below to install the gem.

```bash
$ bundle add importmap-rails
```

Then:

```bash
$ bundle exec rails importmap:install
```

You will find the new `importmap.rb` file in the `config` directory, which somewhat replaces the `package.json` file that read our NPM dependencies.

There, you'll find a list of `pins`.

Packages can be loaded from several sources:

- A URL: `pin "notyf", to: "https://ga.jspm.io/npm:notyf@3.10.0/notyf.es.js"`
- A gem: `pin "@hotwired/turbo-rails", to: "turbo.min.js"`
- A local file: `pin "application"`
- A local directory: `pin_all_from "app/javascript/controllers", under: "controllers"`

## Update

The `import-map` installation has already prefilled the `importmap.rb` file for you.

You should find there the `@hotwired/stimulus-loading` pin, which is a new method of loading for Stimulus controllers that doesn't require manually registering them.

You can now _pin 🍆_ your NPM packages to include them in the import list.

```bash
$ ./bin/importmap pin notyf
```

This command will automatically add all the dependencies of the _notyf_ package.

Here's the list of _pins_ for me:

```ruby
# config/importmap.rb
pin "application", preload: true
pin "i18n", 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/utils", under: "utils"
pin_all_from "app/javascript/controllers", under: "controllers"
pin "trix"
pin "@rails/actioncable", to: "https://ga.jspm.io/npm:@rails/actioncable@7.1.1/app/assets/javascripts/actioncable.esm.js"
pin "@rails/actiontext", to: "actiontext.js"
pin "notyf", to: "https://ga.jspm.io/npm:notyf@3.10.0/notyf.es.js"
```

You can now modify your layout to load the _import-maps_.

```erb
# views/layouts/application.html.erb
<head>
  <!-- ... -->
  <%%= stylesheet_link_tag "trix",
  <%%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>

  <%%= javascript_importmap_tags %>
</head>
```

"We are now loading CSS files manually and one by one, to avoid having a single large bundle and to leverage the capabilities of HTTP 2 for loading multiple files quickly.

## Cleanup

You can now delete all the files related to JavaScript tooling:

```bash
$ rm -rf package.json yarn.lock node_modules
```

Welcome to a rational world without all the complexity of frontend tools! 🥳

If you want to **react to this article** or need **assistance with updating your Ruby on Rails applications**, contact me on [LinkedIn](https://www.linkedin.com/in/nathanleray/), [Mastodon](https://sxnlabs.social/@nathan)."
