12

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:[email protected]/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:[email protected]/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!");
});

4 Answers 4

22

Just switch to CDN other than jspm, jQuery will be global on import:

# config/importmap.rb

# NOTE: pin jquery to jsdelivr instead of jspm
pin "jquery", to: "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.js"
// app/javascript/application.js

import "jquery"; // this import first
import "script"; // then your other imports that use `$`

// NOTE: don't use relative imports: `import "./script"`
//       add `pin "script"` to `importmap.rb`

console.log($); // ok
// app/javascript/script.js

console.log($)  // ok

Everything just works, one import, multiple imports, jquery plugins. No extra hoisting needed.

6
  • 1
    Do you mean that different CDNs deliver different versions of a given package? Like ./bin/importmap pin [email protected] will give me a different version of jquery than ./bin/importmap pin [email protected] --from jsdelivr? I think I must be misunderstanding something, that doesn't seem right. I feel like I'm taking crazy pills. Commented Jan 21, 2023 at 3:55
  • 4
    Oh I see they're very different. How does this make sense to anyone Commented Jan 21, 2023 at 4:12
  • 4
    @FredWillmore jspm is for ESM modules. because of the way the module is built/initialized $ and jQuery don't get exposed globally. I guess there is also some extra processing involved, because this part is changed and no more global jquery. (jsdelivr also has esm option, which does the same).
    – Alex
    Commented Jan 24, 2023 at 5:06
  • 1
    Voting this WAY UP. Thank you!!!
    – nimmolo
    Commented Nov 24, 2023 at 22:31
  • 1
    @raquelhortab app/javascript/script.js
    – Alex
    Commented Jan 2 at 17:36
9

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 break 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.

2
  • 2
    This answer has less upvotes but it's the better answer. This works even with multiple pins. Thx for sharing! Commented Jan 2, 2023 at 8:00
  • 1
    I'm getting GET localhost:3000/assets/src/jquery net::ERR_ABORTED 404 (Not Found) when I try to follow this setup Commented Jul 1, 2023 at 22:47
3

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
1
  • apparently we need to do some more setup in order for this to work? Use specific gem/js package?
    – knagode
    Commented Apr 20, 2023 at 14:23
1

I tried all of the other suggestions here and none of those worked.

Here is how you solve this:

  1. Pin jquery
    bin/importmap pin jquery

  2. Use jsdelivr.net or local file in importmap.rb
    jspm won't work for some unknown reason

    a) pin "jquery", to: "https://cdn.jsdelivr.net/npm/jquery/dist/jquery.js"

    b) pin "jquery", to: "jquery.js"
    if you use a local file, you need to download jquery.js to app/javascript/jquery.js

    You can also pin to a specific version if you want that
    c) pin "jquery", to: "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.js"

  3. In application.js file you only need to add this
    import "jquery"

  4. When you want to use jquery in a view, you need use type="module" on the script tag

<script type="module">

 $(document).ready(function(){
   console.log($)
 })
</script>
2
  • 1
    "In application.js file" => which one? the one in /app/assets/javascripts or /app/javascript ? Commented Jan 2 at 15:09
  • @raquelhortab When you create a new Ruby on Rails project you will only have /app/assets/javascripts/application.js of those two. Commented Feb 9 at 13:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.