Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to migrate requiring of select2.js from sprockets to webpacker

I'm in the process of migrating a Rails 5.1.5 project, which uses CoffeeScript, from using sprockets to using webpacker. The project also uses select2.js. With sprockets, I did the following:

  1. Install jquery-rails (jQuery is a dependency for select2).
  2. Put select2.js code in vendor/assets/javscripts.
  3. In application.js.coffee, add:

    #= require select2
    

After that I was able to use select2 to in my application.js.coffee file:

$(document).on 'turbolinks:load' ->
  $('select').select2

So far I've described the pretty standard way of including/using javascript libraries with sprockets.

However, with webpacker I can't make select2 work and I'm not sure why. I have two hypothesis:

  • I'm not importing/requiring it properly;
  • it doesn't find jQuery at some point of the load process;

So for jQuery, I did the following:

  • yarn add jquery
  • included in my environment.js:

    const webpack = require('webpack');
    
    environment.plugins.append('Provide', new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
    }));
    

I've removed the jquery-rails gem, as well as #= require 'jquery' and tested that jquery works, so I guess I have correctly included it. However, I tried several ways of importing select2 (using es6 imports) and none of them worked. I tried:

import select2 from 'select2';
import select2 from 'select2/dist/js/select2'
import select2 from 'select2/dist/js/select2.js'
import 'select2/dist/js/select2.js'

I even tried to import it from the old vendor location by writing inside app/javascript/pack/application.js.coffee:

import '../../../vendor/assets/javascripts/select2'

I can confirm that the file contents is imported, as I put a console.log within the select2 file under node_modules/select2/dist/js/select.js and it did get printed. However, I also get the error TypeError: $(...).select2 is not a function when I execute $('select').select2() in the browser's dev tool console.

What am I missing or doing wrong?

P.S. I can provide much more info, but I didn't want my question to get any more bloated. P.P.S. With my modest JS knowledge, I looked at the source code but couldn't recognize what exactly they are exporting and how am I supposed to import it.

like image 334
Alexander Popov Avatar asked Mar 21 '18 14:03

Alexander Popov


2 Answers

I know this is an old post, but just in case someone else could benefit:

app/javascript/packs/application.js

...other requires...
require('select2')

window.Rails = Rails

import 'bootstrap'
...other imports...
import 'select2'
import 'select2/dist/css/select2.css'

$(document).on("turbolinks:load", () => {
  $('.select2').select2()
})
like image 57
Thomas Avatar answered Nov 16 '22 15:11

Thomas


My similar problem

I have stumble upon the same problem with another web component (Switchery):

  • I imported the component with yarn add switchery (no error)
  • I could import it correctly through WebPack with import 'switchery' (no error bundling the pack)

But when I was trying to use the Switchery object in the browser like they say in the doc:

var elem = document.querySelector('.js-switch');
var init = new Switchery(elem);

I would get the error: ReferenceError: Switchery is not defined

Note: I didn't want to install RequireJS as WebPack is supposed to do the same thing (and even better) nowadays.

My solution:

The problem was the webpack doesn't expose the pack-generated variables and classes in the global scope!

So to fix this, I needed to do two things:

  • Explicitly give a name to the imported class from Switchery: import Switchery from 'switchery'
  • Use this Class only in the same JS file where the import was done

Testing hack:

If you want to try that out and "go back" to the mess that sprocket allowed, in the same file, you can expose "globally" the variable so you can use in from the browser:

import Switchery from 'switchery'

window.Switchery = Swicthery

now you can execute the switchery almost like in the example: var init = new window.Switchery(elem);

Hope that helps...

like image 38
gfd Avatar answered Nov 16 '22 16:11

gfd