ImportMap

In Rails, the Asset Pipeline library is designed for organizing, caching, and serving static assets, such as JavaScript, CSS, and image files. In this chapter, you will learn about ImportMap that streamlines and optimizes the delivery of JavaScript to enhance the performance and maintainability of the application.

From Version 7, Rails uses ImportMaps as default, enabling building JavaScript applications without JS bundlers like jsbuild. You can still use the JS builders such as esbuild, rollup or webpack by specifying in the rails new command −

Railsnew myapp --javascript=webpack

Install ImportMaps

When the application structure is created without the above syntax, Rails automatically installs the importmaps-rails gem, as it can be found in the project’s Gemfile −

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

You can also install it manually in existing applications −

bundle add importmap-rails
rails importmap:install

Note: ImportMaps are supported natively in all major, modern browsers.

ImportMap helps you to map and load JavaScript modules directly in browser without installing the npm packages with Node.js.

With ImportMap installed, Rails uses it to serve JavaScript by adding the following statement inside the <head> section of the layout template (app\views\layouts\application.html.erb) −

<%= javascript_importmap_tags %>

A file named as application.js is also stored in app\javascript\controllers\application.js which the modular JS files live. Additionally, the config\importmap.rb file the module pins from where the modules are imported. This file is automatically reloaded in Development upon changes, but note that you must restart the server if you remove pins and need them gone from the rendered ImportMap or list of preloads.

typical example of importmap.rb file is −

# Pin npm packages by running ./bin/importmap

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

What is Pin?

pin tells Importmap how to find a JavaScript module that your code is trying to import. It follows the syntax −

pin "module_name", to:"path_or_url", preload:true

where,

module_nameHow you refer to it in import statements
toWhich file it points to (relative path or full URL)
preload(Optional) If true, browser starts loading it early

You can pin a local file from your application’s assets or from a CDN by specifying its URL. For example −

pin "axios", to: https://cdn.skypack.dev/axios

The common pins you find in a typical Rails application are −

Pin commandWhat it means
pin “application”Your main JavaScript file (application.js)
pin “@hotwired/turbo-rails”Makes Turbo available for Turbo Drive/Frames
pin “@hotwired/stimulus”Makes Stimulus JS framework available
pin_all_from “app/javascript/controllers”, under: “controllers”Automatically pins all Stimulus controllers

Note that you can use pin_all_from to pick all files in a specific folder, so you don’t have to pin each module individually.

The pinned modules can be imported in the application.js file, such as −

import {Application} from "@hotwired/stimulus"

You can use JavaScript from Rails frameworks like Action Cable, Action Text, and Active Storage by pinning the libraries manually.

Use Action Cable Channels

In config/importmap.rb −

pin "@rails/actioncable", to:"actioncable.esm.js"
pin_all_from "app/javascript/channels", under:"channels"

In application.js −

import "@rails/actionable"

Use direct uploads for Active Storage

In config/importmap.rb −

pin "@rails/activestorage", to:"activestorage.esm.js"

In application.js −

import "@rails/activestorage"

It makes sense to use logical names that match the package names used by npm, such that if you later want to start transpiling or bundling your code, you won’t have to change any module imports.

To add new npm Packages if your application is supported by importmap-rails, run the bin/importmap pin command from your terminal −

importmap pin react react-dom

Then, import the package into application.js as usual −

import React from "react"
import ReactDOM from "react-dom"

Choosing between ImportMaps and other JS bundlers depends on the requirements of the application. Import maps are the default option because it reduces complexity, improves developer experience, and delivers performance gains. You may need other JS bundlers like webpack if your code requires a transpilation step, such as JSX or TypeScript.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *