Rails Webpacker 3.0 import CSS file is not working - ruby-on-rails

I am working Rails5 project with Webpacker in order to run React properly
But when import my css file inside my root component seems it is not working at all. Looking like stylesheet is not coming at all.
This is my root Component
import React from 'react'
import ReactDOM from 'react-dom'
import StartForm from './insurance_form/start_form'
//import PropTypes from 'prop-types'
import 'react-datepicker/dist/react-datepicker.css';
// not working
ReactDOM.render(
<StartForm />,
document.getElementById('start-form-index-container')
)
This my webpack/environment.js
const { environment } = require('#rails/webpacker')
const merge = require('webpack-merge')
const myCssLoaderOptions = {
modules: true,
sourceMap: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
const CSSLoader = environment.loaders.get('style').use.find(el => el.loader === 'css-loader')
CSSLoader.options = merge(CSSLoader.options, myCssLoaderOptions)
module.exports = environment
So how i can make imported css working well with webpacker?
Thanks!

I had a similar problem just now and found a solution. Hopefully this helps someone else.
I'm using webpacker 3.4.3. It uses the extract-text-webpack-plugin to auto-generate a CSS pack containing the imported styles. It takes the same name as your JS pack. So if your JS pack is hello_react.jsx, and in it you import some CSS like so: import "./Hello.css";, the styles in Hello.css are included in a CSS pack called hello_react.css. In your Rails view you can add something like <%= stylesheet_pack_tag('hello_react.css') %>, and the styles should work.
For more info, see the Link styles from your Rails view section of the Webpacker CSS docs.

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';

Chosen-sprite.png with Wepacker on Rails 6 fails to compile : SassError: Invalid UTF-8 sequence

I am leaving the question as is but please note that I have moved
forward with Select2 and have everything working with the same webpacker
config
I am trying to use the chosen-js lib from webpacker. Webpack does not compile and Rails provides with the following error:
SassError: Invalid UTF-8 sequence
on line 1 of node_modules/chosen-js/chosen-sprite.png
from line 13 of app/javascript/init/index.css.scss
from line 3 of app/javascript/packs/stylesheets.css.scss
>> �PNG
^
# ./app/javascript/packs/stylesheets.css.scss 1:14-220
My environment is configured as follows:
const { environment } = require('#rails/webpacker')
const erb = require('./loaders/erb')
const webpack = require('webpack');
// Add an additional plugin of your choosing : ProvidePlugin
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jquery: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default'], // for Bootstrap 4
toastr: 'toastr/toastr'
})
)
environment.loaders.prepend('erb', erb);
I have deleted the webpack.config that I thought I needed to make chosen-js work and especially load images from the node packages.
Which I import as follows to allow for a multiple select into a rails app (acts-as_taggable_on).
app/javascript/packs/application.js
require("trix")
require("#rails/actiontext")
require("jquery")
require("toastr")
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
// import bootstrap and custom sass files
import "./stylesheets.scss";
//import node lib
import bootstrap from 'bootstrap'
import bootstrapSelect from 'bootstrap-select';
// for stimulus
import "controllers"
// other js libraries
import "../init/index.js";
const importAll = (r) => r.keys().map(r)
require.context('../images', true, /\.(gif|jpg|png|svg)$/i)
then in the init library, I import the file chosen.js which contains javascript is as follows:
import 'chosen-js/chosen.jquery'
import 'chosen-js'
window.addEventListener('DOMContentLoaded', () => {
$("#company_tag_ids").chosen(
{
multiple: true,
allow_single_deselect: true,
width: '100%',
placeholder_text_multiple: "Which are two of most productive days of your week",
no_results_text: "Oops, nothing found!"}
)
})
The form is the following:
<div class="custom-control custom-checkbox chosen-select">
<%= f.collection_select(:tag_ids, ActsAsTaggableOn::Tag.order(:name), :id, :name, { multiple: true, class: 'chosen-select' }) do |b| %>
<% end %>
</div>
Chosen-js works but I cannot get to a form with multi select like the tag_list field in stack over flow. Especially when I try to use the spring-chosen.png, to style it bootstrap way, I receive a missing file error.
Not that I "solved" the missing file error but updating the web pack.config file as initially shown with an url-loader.
Check out the example/chosen branch of my Rails 6 Webpacker demo project. It provides a working demonstration of using Webpack to bundle chosen-js, along with jQuery, to enhance a United States select menu.
https://github.com/rossta/rails6-webpacker-demo/tree/example/chosen
A few recommendations:
Import the chosen css right from your JavaScript. It's not Sass so you may as well co-locate the import with your usage in JS:
import $ from 'jquery'
import 'chosen-js/chosen.css'
import 'chosen-js'
window.addEventListener('DOMContentLoaded', () => {
$(".js-source-states").chosen()
})
You can use the imports-loader to get chosen-js to work with your yarn-installed jquery instance. See https://github.com/rossta/rails6-webpacker-demo/commit/7ee819506d9b60cd296eb36fc8e9414d1e5b377e

How to share variables and functions across multiple client side JavaScript files with Webpacker in Rails 6?

Webpacker packs files like so
(function(module, exports) {
function myFunction() {...}
a consequence of this is that functions and variables from one file are not accessible from another. Or the console.
What's the "rails way" to address this?
Once you move over to Webpacker, you can write your Javascript with modern ES6. This way, we can export and import modules in conventional ES6.
E.g:
// app/javascript/some_module.js
import moment from 'moment';
const SomeModule = {
someMethod() {
return someResult;
}
};
export default SomeModule;
And you can now import this into another module:
// app/javascript/another_module.js
import SomeModule from './some_module';
SomeModule.someMethod();
Notice the folder structure as comments in the file.
You could load the required variables/functions as Webpack plugins using environment.plugins.append in your `config/webpack/environment.js' file.
So, for example, if you wanted to expose $ and jQuery functions from the jQuery module, the file would look like this:
#config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack');
environment.plugins.append('Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
)
Hope it helps!

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

Resources