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.
A 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?
A 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_name | How you refer to it in import statements |
---|---|
to | Which 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 command | What 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.
Leave a Reply