Modularizing javascript code in a Rails app - ruby-on-rails

I am trying to port our rails web app to ember.js (we currently do most of the work rendering views on the server side) and I was wondering how to achieve full modularization of the javascript code. So far, the plugin I liked the most was sprockets-commonjs, which automatically creates commonjs modules for all files that are named .module.js . This would solve most of our problems, except for external libraries, which would still declare globals in the code.
The only solution I can think of is to create common.js modules for each of those libraries.
E.g.: Suppose I want to be able to import Ember.js as a Common.js module. I would then create a file called vendor/modules/ember.module.js, that would contain the following:
//= require ember
module.exports = Ember;
I would then import ember_module (along with the rest of the module wrappers) to the application and use them.
//= require_tree vendor/modules
var ember = require("vendor/modules/ember");
This solution is kinda hacky, but it would improve the modularization of the code. Is there a better way to achieve the same results?

In your ember.module.js, try using //= include ember rather than require. The require directive just adds the file as a dependency; the include directive will actually include the file contents in-place. (See https://github.com/sstephenson/sprockets#sprockets-directives).
Otherwise your solution should work :)

Related

Rails bootstrap gem import vs require

I wanted to use in my rails project bootstrap framework. I used this github repository/instruction to do it: https://github.com/twbs/bootstrap-rubygem.
In the instruction it is underlined that I need to change my application.css extension to css.scss and use only import statements (delete all: //= require). How can I include in my application other css files? With require I could simply type //= require tree . but in this case I have no idea what to do.
You can still use require_tree . but the css files included this way is not compiled by sass and does not have access to sass variables and mixins defined in other files.
The recommended solution is to create one single file (say main.scss) and import all files that require access to site-wide sass resources (e.g. bootstrap variables and mixins). Then you import this one file in application.scss. And you can leave your require tree . there to pick up the rest of the files.

Rails project with React Rails directories?

Image showing my rails structure for react
I have a lot of react components and wish to simply keep them better organized. So I'll cut to the chase and just ask. Is it possible to put my react components in directories and if so- how do I select them in a view and other react components?
I've already tried a few variatians like the one below without success and fear that it's simply not possible? Can't find any documentation about this either.
<%= react_component('OutfitCreate.Images') %>
Edit: To clarify, I want to make it clear that I'm using a typical rails project structure, and for react I am making use of the react-rails gem to handle my components as well as generating them.
Edit2: To clarify further, what I'm seeking is a way to target a react component by directory as such:
<%= react_component('<directory>/<classname>') %>
where each directory will be sub directories of "components".
I know this is an old question but maybe it helps anyone. You can do it like this:
<%= react_component "ComponentFolder/ComponentClassName" %>
It works just fine with rails-react and webpacker.
I recently used the react-rails gem and had a good experience. It takes care of accessing your components in Rails templates and does a few other nice things.
To answer your question specifically, you can put your components inside as many directories as you like as long as you follow the gem docs. The gem provides a view helper that allows you to render a specific component, and to pass data to it as props (the helper takes a hash which becomes the component's props).
Edit -- I'm not sure if you're already using the gem, the helper method you are using looks like it, but you don't specifically mention it. Perhaps there is a problem with the gem installation and/or setup. You need to edit application.js and also to run the generator task: rails g react:install
Edit -- To make sure you can access components in the components subdirectory, you should do the following things:
*run the generator: rails g react:install
*make sure the generated components.js file contains: //= require_tree ./components
*make sure your application.js file contains:
//= require react
//= require react_ujs
//= require components
React components will be considered global, because all .js will be minified in one single big .js file. So, you will have to take some considerations.
First, in your sprockets file (Normally application.js) you need to tell Rails to serve the React Components you want. The easy way would be to require all folders and files in components folder, because all your components will be there, but organized in subfolders. This is made adding the next line:
// File: app/assets/javascripts/application.js
//= require_tree ./components
Second, if you want to use your React component named for example Images, which could be defined in ../components/folder/images.js, you just could use in your Rails View the helper react_component('Images') like usual.
React will find the Images component if it match with the Images component you defined inside some served .js (But a sane human will expect you defined the Image Component inside some images.js) because this name Images is global (Remember? One big .js file will be served).
With this approach, the client will download only one big .js file with all your React Components. Bad for download speed, but could be cached.
So, here, you would have to take care to name all components with a different name each one.
Now, if you have for example a component named Foo inside ../components/folder/doesnt_matter.js and another component with the same name Foo, but inside ../components/another_folder/this_neither.js, you will have to tell Rails which file do you want to serve for the specific View you want to render to evade collision name problems.
This means, you could make the client to download only the needed js code (and the needed React Components) for the rendered page. It will be downloading .js files for each page, losing the cache possibility.
One intermediate way to do this, would be to serve a middle sized .js file for all the views in the same controller.
To do this, you could organize your js (or jsx, or ...) in a way you could have a place for common Components (which are used in two or more controllers), and a specific folder for each controller with specific React Components in there.
First, you will have to replace the previously added //require_tree ./components in application.js with //require ./components/common/ for serving only the common React components to All Views.
Second, in your layout, you could serve two js files; an application.js and a #{controller_name}.js (This means, one specific .js file per controller).
Third, for each controller, you will have a .js file with the same name. So, supose you have a controller called home_controller, then, you will need to have a home.js (controller_name helper in layout view will make rails to look for this file) and in it, using sprockets again, you will serve specific React Components with //require ./components/home/
In this way, you will have to take care of your organization, and the React Components Names need to differ with the ones inside .../components/common/.
If you want to be more specific yet, you could use the same technique in layout in combination with controller_name and action_name helpers. Or you could use content_for asking for the specific .js files that have the React Components the View needs.
However, you need to be carefull because i don't know how crazy the Assets Pipeline could turn against you. Specially using content_for.

RoR asset pipeline best practices for one-off JS plugins

I have a best practices question regarding one-off javascript plugins and their role in the Rails asset pipeline.
I'm new to Rails, and am working on a new project. The site template I'm using uses a large collection of js plugins for added functionality. (eq chartjs.org, ckeditor, and about 40 others) Since these are needed on a page-by-page basis, I'm not sure if I should really load them all in the application.js manifest.
Currently, I have the template's assets under the /vendor directory and only the core assets are being loaded from my application.js manifest.
Thoughts on how/where to include the plugins?
As i know that rails default added all js file include in application.js by //= require_tree . so, you can remove it and add only those file which you want to added. and if you want to run only specific function then you can use location.pathname with condition and it will work for only that specific page.

Angular ui bootstrap custom templates in Rails

How can I use the custom templates of angular ui bootstrap in rails?
I mean, if I use pagination for example it will look for a templates/pagination/pagination.html template.
The problem is that rails won't serve templates in that path, it actually needs to be assets/templates/pagination/pagination.html using the <%= asset_path(....) %> helper.
Hacking the angular ui bootstrap javascript file is a way, but I don't feel like hacking it every time I get a new version.
What I would suggest is to bundle custom templates with the library itself or inside a separate file. The technique to use is to fill in $templateCache with the content of your custom templates. Have a look at one of the files distributed with tamplates to see what I mean:
https://github.com/angular-ui/bootstrap/blob/gh-pages/ui-bootstrap-tpls-0.3.0.js#L2042
You can bundle templates into the $templateCache as part of the build process or prepare this file manually (in this case you need to write templates as JS strings).
Downloading individual templates via XHR for each and every directive would be wasteful as it would result in many XHR requests and would slow down your application. Also, if you preload templates into the $templateCache you can specify required path, one that doesn't need to be a valid path on your WWW server.
I use bower to manage my js libs.
Hence I have these files in my vendor/assets/javascripts/ folder:
angular-ui/bootstrap-bower
With these files, you can simply require them in your javascript manifest file (usually application.js)
//= require angular-bootstrap/ui-bootstrap
//= require angular-bootstrap/ui-bootstrap-tpls
and then you don't need to specify any templates if you want to use the default built-in templates.
I find this solution in the following url
Ref:angular-ui-bootstrap-directive-template-missing

Rails 3.1: Possible to include jQuery from Google's CDN in application.js?

I wanted to know if it's possible to include an external file in the application.js file so it gets combined with the rest of the .js files in the apps/assets/javascript folder
Is there a way to get the following code work in the application.js file:
//= require 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'
or something :p
Why would you want to do that? The whole idea of using a CDN is not to load content from your server but other content server. If you would like it to be compiled, just download it to the app/assets/javascripts directory and require it. It is much cleaner that way.

Resources