How can I install jQuery in Rails 7 with importmap?

Viewed 1025

I have a new Rails 7 application. I'm currently trying to learn all the new features since Rails 5. I want to use the following code in my javascript file, but so far I'm getting the following error: Uncaught ReferenceError: $ is not defined.

$(document).on("turbo:load", () => {
  console.log("turbo!");
});

Here are two other relevant files. If I need to post anything else please let me know.

importmap.rb

pin "application", preload: true
pin "jquery", to: "https://ga.jspm.io/npm:jquery@3.6.0/dist/jquery.js", 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 "el-transition", to: "https://ga.jspm.io/npm:el-transition@0.0.7/index.js"

pin_all_from "app/javascript/controllers", under: "controllers"

application.js

import "@hotwired/turbo-rails"
import "jquery"

$(document).on("turbo:load", () => {
  console.log("turbo!");
});
3 Answers

When using jspm jQuery has to be explicitly imported:

// app/javascript/application.js

import jQuery from "jquery";

// NOTE: make jQuery global if needed
window.$ = window.jQuery = jQuery;

console.log($); // ok

Another way is to switch to CDN other than jspm:

# config/importmap.rb

# NOTE: pin jquery to jsdelivr instead of jspm
pin "jquery", to: "https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.js"
// app/javascript/application.js

import "jquery";
console.log($); // ok

Related: How to use jqueryUI in a rails 6 or rails 7 alpha engine

I needed to add a few lines to my application.js file.

import "@hotwired/turbo-rails"
import jquery from "jquery"
window.jQuery = jquery
window.$ = jquery

Doing what the other answers say will work, but it will stop working when you pin a new package.

The reason is the so-called javascript hoisted way of working, which means that it will reorder the code you have to reorganize the imports in blocks. This will brake jQuery window assignation.

To avoid that, extract

import jquery from "jquery"
window.jQuery = jquery
window.$ = jquery

in another file and call it in on single import.

In my case, I have:

application.js

import "./src/jquery"

$(function(){
  console.log("Hey!")
})

and src/jquery.js with above's code.

Related