Embracing New Asset Management in Rails 7.1: Switching to importmap-rails and dartsass-rails
Tags: rails, importmap, dartsass, assets
Published: 2024-01-28 00:41:20

## Using importmap-rails and dartsass-rails instead of jsbundling-rails and cssbundling-rails in Rails 7.1

In the dynamic landscape of Rails development, selecting the most efficient and practical tools for JavaScript and CSS management is key. While Rails 7.1 continues to support traditional approaches like jsbundling-rails and cssbundling-rails, the Rails community has been exploring compelling alternatives. Among these are importmap-rails and dartsass-rails, which offer a more streamlined and modern asset management strategy. This guide will show you how to migrate from the conventional bundling tools to these newer options, enhancing your Rails 7.1 application's asset handling.

## Prerequisites

Before diving into this guide, make sure you're familiar with the basics of Rails, Ruby, JavaScript, and CSS.

## Why Choose importmap-rails and dartsass-rails?

`importmap-rails` and `dartsass-rails` offer several benefits over their predecessors:

- Simplified project setup with fewer dependencies
- Enhanced performance due to more efficient asset handling
- Reduction in external tooling reliance, like Node.js and Yarn

## Step-by-Step Migration Guide

### 1. Update Your Gemfile

Remove the old gems and add the new ones:

```ruby
# Remove these
gem 'jsbundling-rails'
gem 'cssbundling-rails'

# Add these
gem 'turbo-rails'
gem 'importmap-rails'
gem 'dartsass-rails'
```

### 2. Install the New Gems

Run these commands to install and set up the new gems:

```sh
bundle install
./bin/rails importmap:install
./bin/rails dartsass:install
```

### 3. Configure Your Procfile.dev

Replace the yarn build commands with the appropriate Dartsass command:

```sh
css: bin/rails dartsass:watch
```

### 4. Customize Dartsass Configuration

Create a new file `config/initializers/dartsass.rb` with the following content to customize the CSS build process:

```rb
Rails.application.config.dartsass.builds = {
  "application.scss" => "application.css"
}
Rails.application.config.dartsass.build_options = " --style=expanded"

```

This configuration prefers expanded CSS for better readability and includes source maps.

### 5. Update application.html.erb
Ensure you have replaced `javascript_include_tag "application"` with `<%= javascript_importmap_tags %>`.

## Configuring Import Maps and Dartsass

### 1. Default Manifest Setup
Your app/assets/config/manifest.js should look like this:

```js
//= link_tree ../images
//= link_tree ../../javascript .js
//= link_tree ../../../vendor/javascript .js
//= link_tree ../builds
```

### 2. Import Map Configuration
Set up your `config/importmap.rb` to manage JavaScript dependencies:

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

### 3. Imports in application.js File
Organize your JavaScript imports in `app/javascript/application.js`:
```js
import "@hotwired/turbo-rails";
import "controllers";
```

### 4. Stimulus Controller Management
Opt for lazy loading in `app/javascript/controllers/index.js` to improve performance:
```js
import { application } from "controllers/application";
import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
lazyLoadControllersFrom("controllers", application)
```

## Adding External Libraries

### 1. Importing Libraries
Example: Adding `moment-timezone.js`:
```sh
./bin/importmap pin moment-timezone
```

This command downloads and saves 2 files: 
  - https://ga.jspm.io/npm:moment-timezone@0.5.44/index.js to `vendor/javascript/moment-timezone.js`
  - https://ga.jspm.io/npm:moment@2.30.1/moment.js to `vendor/javascript/moment.js`

The command also updates `config/importmap.rb`:
```rb
pin "moment-timezone" # @0.5.44
pin "moment" # @2.30.1
```

Now you can import from your .js file:
```js
import moment from "moment-timezone"
```

### 2. Handling Custom JavaScript Files
Example: Including 2 custom JS files located at 

`vendor/folder/subfolder/js1/hi.js` and `vendor/folder/subfolder/js2/hello.js`



Update `config/initializers/assets.rb`:
```rb
Rails.application.config.assets.paths << 
Rails.root.join("vendor/folder/subfolder")
```
Modify `app/assets/config/manifest.js`:
```js
//= link_tree ../../../vendor/folder/subfolder
```
Add entries to `config/importmap.rb`:
```rb
pin "hi", to: "js1/hi.js"
pin "hello", to: "js2/hello.js"
```
Import them in your JavaScript files:
```js
import "hi";
import "hello";
```

## Conclusion
After you are done adding all external libraries using pin in importmap.rb, you can delete the unused package.json file and node_modules folder.

Switching to importmap-rails and dartsass-rails in Rails 7.1 offers a more efficient and streamlined way to manage your JavaScript and CSS. This guide should help you make the transition smoothly. Feel free to share your experiences, ask questions, or provide feedback in the comments below.

Happy coding!