How to migrate requiring of select2.js from sprockets to webpacker - ruby-on-rails

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:
Install jquery-rails (jQuery is a dependency for select2).
Put select2.js code in vendor/assets/javscripts.
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.

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()
})

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

Related

Rails 6 select2 is not defined

Im using rails 6 with webpack, and for some reason I cannot use select2 when I try to respond a js file the following:
$("#select-search-bar").select2()
How can I manage to use select2 in the js respond
Here is my application.js file:
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require('font-awesome/css/font-awesome.css')
require("jquery")
require('cocoon-rails/src/cocoon')
require('chart.js/dist/Chart')
require('materialize-css/dist/js/materialize')
require('../stylesheets/application')
require('packs/dashboards')
require('packs/relateds')
require('packs/banner')
require('packs/users')
import 'packs/select2'
require('packs/resources')
// packs/select2.js
import $ from 'jquery';
import 'select2/dist/js/select2.min'
My guess is your app/webpacker/packs/application.js is not configured correctly.
For example this is what I have:
require( 'select2' );
import "select2/dist/css/select2.min.css";
Make sure you've added Select2 with yarn add select2 see more here. It is possible to have Select2 translated as well by adding your locales like this:
require( 'select2/dist/js/i18n/en.js' );
require( 'select2/dist/js/i18n/lv.js' );
In case you need bootstrap theme, you can add it as well, for example, Bootstrap3 with yarn add select2-bootstrap-theme and then in your app/webpacker/packs/application.js
import "select2-bootstrap-theme/dist/select2-bootstrap.min.css";
In case this doesn't help, probably you have some error in your console and you might be interested to check that.

TinyMCE w/Rails 6 and webpacker - no icons, turbolinks

We are trying to upgrade our app to Rails 6 with Webpacker (and Stimulus). Things are going fine except for TinyMCE. We have 2 problems, I will ask them in separate SO questions.
We installed TinyMCE using
yarn add tinymce
and have version 5.3.0
In our stimulus controller header we have:
import tinymce from 'tinymce/tinymce';
import 'tinymce/themes/silver';
import 'tinymce/skins/ui/oxide/skin.min';
import 'tinymce/skins/ui/oxide/content.min';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/link';
And then in the controller connect block we have:
connect() {
console.log('gonna reload');
require.context(
'!file-loader?name=[path][name].[ext]&context=node_modules/tinymce&outputPath=js!tinymce/skins',
true,
/.*/
);
tinymce.init({
selector: '.tinymce',
plugins: ['paste', 'link'],
skin: false
});
}
This is code that essentially works, except that in the console I see:
VM40 application-68201fac0dcbbcb543e0.js:213771 GET https://xxx.ngrok.io/packs/js/icons/default/icons.js net::ERR_ABORTED 404 (Not Found)
VM40 application-68201fac0dcbbcb543e0.js:224775 Failed to load icons: default from url https://xxx.ngrok.io/packs/js/icons/default/icons.js
Do we need another require.context to handle the loading of those?
It looks like TinyMCE no longer loads the icons dynamically, so Webpack must be instructed to include them in the bundle manually. Adding the icons import after the tinymce import worked for me:
import 'tinymce/icons/default';

Ignore the require statement on webpack 2 bundling time and exclude that require statement from the bundled js

I implement a React.Component in a.js. This file will be used for client and server side rendering. Of course a.js has require("a.scss")
Is there a way to do on webpack.config.js only to tell webpack not to read all the scss` require statement during the bundling?
I did try the IgnorePlugin to *.scss. The bundling process is fine but node gives runtime error which is Cannot find module './a.scss'
Here are the unwanted suggestions
I don't want to use DefinePlugin or EnvironmentPlugin because I don't want to wrap the require("a.scss") inside an if statement
I don't want to use ExtractTextWebpackPlugin to extract the scss which is I am currently using. Let node can run the bundled js perfectly.
This is the solution
{
"test": /\.s?css$/,
"use": "null-loader"
}

jsx doesn't seem to transpile correctly

I am using the react-rails gem in a Rails(4.2.7) project. This is the only modification I've made to my default Gemfile:
gem 'react-rails'
I've defined a component in a .jsx file using es6 syntax:
class Foo extends React.Component {
render () {
return (<h1>hello</h1>)
}
}
This works fine, but when I attempt to import a js module, I get an error:
import ReactTransitionGroup from 'react-addons-transition-group'
class Foo extends React.Component {
render () {
return (<h1>hello</h1>)
}
}
foo.es6.self-69f3a42….js?body=1:11 Uncaught ReferenceError: require is not defined
It seems to me that if I'm not transpiling the jsx correctly then I would be getting an error in the first case, but I'm not. I've been using jsx all day long with no issues until I tried to use import.
I've tried adding the following to my Gemfile:
gem 'sprockets-es6'
gem 'babel-transpiler'
I've tried adding this to config/environments/development.rb:
config.react.jsx_transformer_class = React::JSX::BabelTransformer
And I've tried generating the component using the rails react component generator with the --es6 flag:
rails g react:component Foo --es6
What am I missing?
So here's how I resolved my issue: since I'm using the 'react-rails' gem, the addons are available via a configuration option - I added the following to config/application.rb:
config.react.addons = true
Then in my .jsx file, instead of import, this is the syntax I used to have access to ReactTransitionGroup:
var ReactTransitionGroup = React.addons.ReactTransitionGroup
I still don't understand, but maybe someday I will, why the import statement transpiles to require which is undefined, and how that could be fixed by anything other than defining require, or transpiling to something that is defined.

React Rails Component is not defined

I'm trying to get the react-rails gem (version 2.1) working in my Rails 4.2.4 app. I've gone through the setup steps in the Readme and I'm using webpacker for the js preprocessing. I have a component inside of app/javascript/components/label.js that looks like this:
import React, {PureComponent} from 'react';
import ReactDOM from 'react-dom'
export default class Label extends PureComponent {
render () {
return (
<div>Something rendered in React</div>
)
}
}
And then I reference this in my view with the following line:
= react_component("Label")
As far as I can see from the Readme, this should be all that is necessary in order to render the component (provided the application pack is included in the layout, which it is)
= javascript_pack_tag 'application'
So I'm confused as to why I'm getting the error in my browser that the component is not defined.
Uncaught ReferenceError: Label is not defined
Opening app/javascript/packs/application.js I can see the following:
console.log('Hello World from Webpacker')
// Support component names relative to this directory:
var componentRequireContext = require.context("components", true)
var ReactRailsUJS = require("react_ujs")
ReactRailsUJS.useContext(componentRequireContext)
First I verified that the console log is displayed in the browser (it is). I'm not sure what componentRequireContext does, but if it is relative to the current file, then it seems odd that it points to components and not ../components, but changing this doesn't render the component. However, I can get the component rendering if I add the following line:
window.Label = require('../components/label.js');
I thought the React Rails gem took care of this though, provided the components were saved in the app/javascript/components directory? There's nothing in the Readme that says that I need to explicitly declare and require the component, or am I mistaken?
It looks like you have a capitalization issue. You named the file 'label.js' but you are looking for '= react_component("Label")' So it looks and doesn't find what Label is. Then when you set Label on the window then react is like "Oh ok, Label is actually label.js." and it does stuff. TLDR capitalization matters.

Resources