Rails: Accessing JS module methods from files served by webpacker - ruby-on-rails

Context
I try to move assets in our application to webpack using Webpacker gem. Application is very big, so I need to do it partially.
What did so far...
I successfully managed to call the script using javascript_pack_tag
I export a super simple module:
# javascript/src/javascript/test.js'
const Direction = {
log_to_console: function(){
console.log('test');
}
};
export default Direction;
Then import it in the application entry point
# javascript/packs/application.js
import Test from '../src/javascript/test.js'
Test.log_to_console();
Finally rendering it in the layout:
# app/views/application.slim
= javascript_include_tag 'application'
The result is: "Test" string visible in the browser console.
The problem
Currently in the whole application we use Modules in views like this:
# app/views/assets/javascripts/test.coffee
log_to_console = ->
console.log('test');
#Test = { log_to_console }
# app/views/some/template.slim
javascript:
Test.log_to_console()
But after moving module to webpack I can't access the Test module anymore.
So my question is:
How to configure webpacker gem OR refactor the code above to make the log_to_console() method available in views/browser inspector?
Ideally it would be if we could also access them in old javascript files compiled by sprockets.

I figured out that solution for now. May be helpful for anyone that encounters that problem.
If anyone finds better solution, I would be glad to see it here ;).
For now all our modules/libraries that are needed to be visible in views/other coffee files, I just set as globally available via the window object.
import Foo from '../src/javascript/foo.js
window.Foo = Foo
I know it's ugly anti pattern, but works well as temporary solution until we update our scripts behave more like independent packs.

Related

how to install easydropdown with Rails 6

What is the correct way to install easydropdown into Rails 6?
I ran yarn add easydropdown to add it to my app. Seems ok; I verified that my browser sees it in the js sources.
After this, not totally sure what to do. In app/javascripts/packs/application.js, I've tried adding these lines. None cause errors.
require('easydropdown')
import easydropdown from 'easydropdown'
import Easydropdown from 'easydropdown' - does case matter?
But in my page and js console, I keep seeing easydropdown is not defined.
What am I missing?
When using webpack the require statements are not global so you need to require the library in the file in which you are using it.
In your application.js pack file add the following:
import easydropdown from 'easydropdown';
document.addEventListener("turbolinks:load", () => {
easydropdown('.easydropdown')
});
as long as your selects have class of "easydropdown" this should make them all work.
Your styles need to be added either in your assets or imported in this pack file as well.
Thanks to #ben-trewern for helping me get here.
For Rails 6, here's what works for me:
yarn add easydropdown to install it into your Rails App
Append loader code to app/javascripts/packs/application.js.
I've found 2 ways that work. I honestly don't know which is better or why.
Option 1: using import
import easydropdown from 'easydropdown';
window.easydropdown = easydropdown;
Option 2: using require
const easydropdown = require('easydropdown')
window.easydropdown = easydropdown.default
Now you can use easydropdown functions in your views (including <script> tags).
Bonus help: Are you using Stimulus JS?
If your dropdown is connected to a Stimulus controller, here's some tips:
I found that I still had to assign window.easydropdown (above) in order to call EDD in my controller code.
Seems the most straightforward thing to do is to call easydropdown.select('#my-select') in my Stimulus controller's initialize() method, e.g.
export default class extends Controller {
static targets = [...]
initialize() {
easydropdown.select('#region-switcher`);
...
}
...

How to include SCSS files for Angular 5 in Rails 5 with Webpacker

I'm trying to setup a new Rails project with webpacker and Angular. The basic setup is working, but I'm not able to include custom SCSS files. I followed the steps in the blog post Angular with Rails and Webpacker, but I wasn't able to get it up and running. I end up with the error
ERROR in ./node_modules/css-loader??ref--2-2!./node_modules/postcss-loader/lib??ref--2-3!./node_modules/sass-loader/lib/loader.js??ref--2-4!./node_modules/to-string-loader/src/to-string.js!./node_modules/css-loader!./node_modules/resolve-url-loader!./node_modules/sass-loader/lib/loader.js!./app/javascript/hello_angular/app/app.component.scss
Module build failed:
h1 {
^
Invalid CSS after "": expected 1 selector or at-rule, was "var result = requir"
in /Users/florianfeldhaus/IdeaProjects/rails-test/app/javascript/hello_angular/app/app.component.scss (line 1, column 1)
I documented all steps I carried out (I tried first without and then with the hack described in the blog post), but couldn't get it to work. I shared a minimal project (e.g. without the HTML template) on GitHub.
What do I need to do to include SCSS files for an Angular 5 App served with Rails 5 with Webpacker?
Is there any full, up to date tutorial or documentation available for this setup?
I finally found the answer to this myself. I believe the problem is that the sass-loader is already being included somewhere by default. When you go to add it to your loaders in environment.js, it's actually trying load sass-loader twice and causing a cryptic error. So the solution is to use the following code to overwrite the existing entry and then also include css-loader and to-string-loader in order to include it in your Angular component.
environment.loaders.insert('sass', {
test: /\.scss$/,
use: [
"to-string-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS
]
});

Rails and CoffeeScript compile error in production

Somehow in development environment my coffeeScript files compile correctly. But when I compile them for production I get something like this
CoffeeScript:
$->
alert "hello world"
Compiled to Javascript
(function() {
$(function(){
alert("hello world");
})
}).call(this)
I have checked for miss indentations and spacing errors, or for a mix of tabs and spaces but there are not any. The weird thing is that when I converted the with the compiler from coffeescript.org it compiles correctly, its just in the production environment. Any ideas?
by the way: I am using rails 4
It's a coffeescript setting.
(function() {
# Code here
}).call(this)
Is a closure generated by coffeescript by default (can be disabled, but you shouldn't), used to avoid global namespace pollution.
It doesn't affect the script execution, your jQuery code will still be run once document is loaded.
Important note
The only issue you may find with that closure is that you actually have hard time declaring global variables. This can be solved in this way:
window.yourvar = 'something'
There is also a suggestion here on how you can disable it anyway: How can I use option "--bare" in Rails 3.1 for CoffeeScript?

Class Loading in Phalcon for plugins

When adding a dispacher in the services.php it doesnt seem to have access to the autoloader to include class's.
Example: /config/services.php
$di->set('dispatcher', function() use ($di) {
require __DIR__.'/../../app/plugins/security.php';
$eventsManager = $di->getShared('eventsManager');
$security = new Security($di);
$eventsManager->attach('dispatch', $security);
$dispatcher = new Phalcon\Mvc\Dispatcher();
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
Is it correct to include the require? Its the only way I can seem to have access to the security plugin? Im sure there is a better way?
Both https://github.com/phalcon/invo is different to the demonstration on the Phalcon homepage?
Anyone clarify?
If you plan move your plugins directory to another directory there is a high possibility of breaking the application due to the static paths. An autoloader gives you the freedom to re-organize the application by just adjusting the paths on it.
The INVO application uses an autoloader:
Set a plugins directory:
https://github.com/phalcon/invo/blob/master/public/index.php#L20
Use the class with auto-loading:
https://github.com/phalcon/invo/blob/master/public/index.php#L38
I think public/index.php is a better place for require or in the same place you can use a loader

how does the gem backbone-on-rails generate its templates

I'm trying to understand how the gem backbone-on-rails works under the hood.
My problem right now is that I don't know who is in charge of generating the code for the templates it provides.
After installing and setting it up (I'm using the plain js route, not coffeescript, but the question is the same), if I write a template file in /app/assets/templates/hello.jst, it gets "somehow" translated to the following javascript inside application.js:
(function() {
this.JST || (this.JST = {});
this.JST["hello"] = function(obj){ <ugly js here> };
);
But who actually does generate that code? I've browsed the sourcecode of backbone-on-rails, and could not find anything that pointed to template compilation. Is the asset pipeline capable of doing that out of the box?
Ok, I think I found my answer.
The functionality is provided by sprokets, there is a good explanation on its readme.
Will close this in two days.

Resources