Serverside rendering react components in Ruby on rails project without asset pipeline - ruby-on-rails

I'm working on a Ruby on rails 4 project where we are using React/Redux for frontend. We are using Webpack and gulp for compiling javascript and css. We do not use rails Asset pipeline at all, it is disabled from config. All assets compile to public folder and directly included on views. Now all react components are rendering on client side. It is having his own disadvantages like visual flicks before js is fully loaded and problems on passing initial props from backend to frontend.
Is there any good way to compile react components on server side without using asset pipeline and passing props directly from rails views?

I am pretty sure http://reactrb.org does this, but it does use asset pipeline. The webpack components are brought in to the rails side, and then wrappers are automatically built so you can interface to the webpack components from your client side ruby components.
There was a lot of discussion on this at https://gitter.im/reactrb/chat and I don't know the details.
Also tutorial here: http://tutorials.pluralsight.com/ruby-ruby-on-rails/reactrb-showcase dealing with this issue as well.
So you could just use http://reactrb.org or figure it by reading their code.

Related

Connecting Front End and Backend - Rails and Vue

I am a little confused on this.
If in Rails, with erb files we can build pages layout, 1) in what situations would we use webpacker to add vue.
What i understand so far is a Vue application would at times make a request to the server lets say to populate data. 2) Would that be the only use or are they other uses cases?
Also 3) is it best to generate a vue or angular app as a standalone (like vue create app so vue is in a front end folder and rails in a backend folder) or to use webpacker in rails
I'll try and answer your three questions at once, hope that's ok!
There are three common ways you can integrate Vue.js (or any JavaScript) library into a Rails application:
You can load it through sprockets, which is the built-in Rails asset packaging library. You would do this if your application is mostly going to be statically rendered and NOT a SPA (Single Paged Application). Sprockets is very tightly integrated with Rails, allowing you to refer to assets in your Rails templates and code. However, Sprockets is quite far behind Webpack in terms of the actual bundling/packaging, optimizations, and ease of use for any complex JS project. So you would only want to do this if you're adding a tiny amount of interactivity to a mostly static website.
You can load it through Webpacker. The idea of Webpacker is to give you a really easy way to start building a SPA with a rails backend. So you receive all the benefits of Webpack but don't need to tweek many configurations (at the start), or set up a separate web server, or worry about CORS. It's great for starting a new project/prototyping in or progressively integrating Vue.js into a larger static website. The downside is that Webpacker uses webpacker.yml for its default configuration which adds unnecessary confusion when you will eventually need to have more complex configs.
Finally you can load it through a separate web server ("standalone"), and in the long run, this will give you the greatest degree of freedom through less Webpacker middleware and access to the most updated webpack version. It also offers you the ability to scale, secure, and do fancy stuff like Server Side Rendering. The downside is this does require the most upfront setup and long-term maintenance time. AFAIK this is the most common way companies serve SPAs.

Adding Lodash to a new Rails 5.2 app with webpacker

So, using Rails 5.2beta (gem install rails --pre), if you create a new app via rails new myapp --webpack=react... how would I go about incorporating Lodash into my flow from there?
I've mucked around with babel-plugin-lodash and lodash-webpack-plugin to no avail.
The compile doesn't fail if I do something like import { _pick, _map } from 'lodash/array'; ... but those variables are undefined when trying to use them.
I'm a bit lost as I'm both new to webpacker & webpack, and a lot of existing examples seem to target an older version of webpack?
Anyway, thank you for any help...
UPDATE:
Ok, looks like you can just do import map from "lodash/map"
So where are you trying to use lodash from? By this I mean are you sure the files are getting compiled / processed by Webpacker, or are they getting processed via the Asset Pipeline?
On my webpacker project I realized that there's a problem: that yes, regular old Javascript compiled with the Asset Pipeline won't know about the NPM Modules included via Webpack. (or at least the require statements wouldn't work).
Because of this I made a hard rule: all javascript goes where webpacker expect it (app/javascript) and no Javascript goes in app/assets. We only use the asset pipeline for CSS (which works great in our case, as I still don't think React - our frontend framework of choice - has a good story around site wide CSS).

React, Rails, Webpack: Best practice for where to place React.render

I have a rails app currently using webpack to create a bundle.js file that is picked up by the asset pipeline.
If I have a page that needs a react component embedded in it, where is the best place to actually call React.render? The react-rails gem does a great job of doing this unobtrusively, but with webpack I just have an entry.js file. Embedding a <script> tag in the page seems wrong (and also doesn't work because the JSX isn't transpiled). Is the right approach to jus have a script (probably in entry.js) that looks for certain placeholders on the page and replaces them with react components on page load?
thanks!
Yes. If you look at the react-starter-kit repo which people have started to use when they begin a new project, the recommended minimalistic way is having a div after your body and loading the bundled js afterwards.

Angular + .nghaml template: Referencing Precompiled Image Assets

I'm using .nghaml for my templates and using the following gems for Angular integration:
gem 'angularjs-rails'
gem 'angular-rails-templates'
My Rail view layouts are name.html.haml and using image_tag within them works fine. On production I can see the images.
In contrast, in my Angular templates (assets/template) with their .nghaml extension I can not use Rails helper image_tag and a direct reference does not work
%image(src="assets/sample_image.png")
The direct reference works locally, but on production images don't render.
This person (Rails Image assets in Angular Directive and template) had a similar issue, but using
%img(ng-src='assets/sample_image.png')
worked locally but not in production. And attempting to use image-url results in the error of undefined method (just as image_tag) because none of the Rails helpers seem to be working in the .nghaml extension.
The images that are working (Rails views with image_tag helpers) are referencing the precompiled assets which have their names changed with the addition of a md5-hash (based on the first linked article), but I'm having issues figuring out how to tell the nghaml templates what the new precompiled assets are called without a Rails helper method.
I ran into this issue with helpers a few months ago (Rails App to Angular: HAML + Rails Helpers) and didn't find a solution, but only recently needed to get images into nghaml templates rather than just creating what I needed with CSS.
I'm currently planning to just move the angular templates back to erb if I can't get this figured out, but if there are alternatives (or solutions) I'm unaware of, I'd love to hear them.
The solution proposed in the post Rails App to Angular: HAML + Rails Helpers will allow you to use the helpers (including the image_tag helper) in your haml files when generating the client-side html files.
One issue: According to the official repo for the angular-rails-template library, the .nghaml extension is no longer supported. You have to rename it to .haml
The bigger issue is that you're using Rails to serve a single-page JS app. There's no need for this, you can serve the site using nginx or Apache and control the caching and do cache busting there (nginx & apache cache busting tutorial)
If you're using Rails for the REST API, it should be de-coupled from your frontend AngularJS app.
If you're trying to do some fancy stuff in the templates aside from the cache busting, you should be doing it in JS and plain HTML. It's weird and strange but AngularJS and other frontend MVC/MVVM frameworks are different beasts compared to Rails and Django and the server-side MVC frameworks.

Separating Angularjs and Rails apps as standalone components

I wanted to try out Angularjs. However, I have been trouble deciding on where I should located my angular app.
I am using Rails framework for the backend. I have seen tutorials where the entire angular app lives under the assets/javascript folder.
I was wondering if instead of living within the assets/javascript folder, I could make it live outside my rails directory entirely. That way, I can potentially separate my backend and front end entirely. (Is this recommended?).
I believe the asset pipeline also precompiles a lot of the assets. If I were to separate out the angularjs asset, would I need to precompile the assets somehow?
Thanks
I've been working through a similar set of questions. There are some good tools that allow you to integrate AngularJS directly into your rails asset pipeline, and they to me look good if you want just a little bit of Angular.
However, if you want a full Angular front-end, aka a single page web app, I think you'll eventually be limited by compatibility and some of the tooling. I feel like the Rails gems won't quite keep up with Angular, and so you'll be into version conflicts. I've also seen more and more tooling for Angular as a standalone, and I very much like the ng-boilerplate project template. I also like much of the testing tooling such as karma, and I haven't really sorted out a way to integrate karma with rails.
For that reason, I eventually decided that I'd keep the two separate. Initially, I did that through creating a rails application and a separate angular application (separate directories). I used ng-boilerplate as the framework for the angular end. I wrote a tutorial on that. This eventually got a bit frustrating, and I wrote some more thoughts on it, the main annoyance was that I had two git repositories and it was annoying to keep them in synch. It's also sort of annoying working with an IDE across two directories. I've ended up shifting to rails and angular being in the same folder, and they seem to play nice, as each uses different directories within that project.
In this current structure, I'm using the grunt setup that came with ng-boilerplate to minify all the code, package it and also run karma unit testing. I haven't yet nailed the end-to-end testing, but it's on my list. I've found this to be a relatively productive work environment. My chosen structure for my pages, controllers and karma test cases has some repeated code (I'm choosing not to factor it out to maintain readability). I'm planning to extend the rails scaffold generator to create the javascript framework for me - so when I create a persons rails scaffold, it will also create a persons angularjs scaffold for me. I'll update here if and when I do that work.
EDIT: I've completed the scaffolding work as well, which allows rails to automatically generate the angularJS elements when you generate the rails models/controllers etc. The blog post is here: http://technpol.wordpress.com/2013/09/24/rails-generator-to-generate-angular-views/
You could use a grunt based workflow:
How to manage AngularJS workflow with lots of script files
http://newtriks.com/2013/06/11/automating-angularjs-with-yeoman-grunt-and-bower/
If you start with a decoupled frontend, use mocks at first so you can stay within angular and not lose focus switching between backend and frontend logic. An advantage of building a single page application is that you can develop it independently of the backend api. See (http://docs.angularjs.org/api/ngMockE2E.$httpBackend) for information about mocking http responses.
We have been using AngularJS with our Rails application, in a way where we have been using Rails ERB templates, but switch over to using ng directive as and when required.
For this above setup we have used bower/bower-rails gem, which lets us use bower to manage the angular packages and their dependencies. We commit this into our repo, in the javascripts directory, and is taken care of by the Rails asset pipeline.
This setup has worked well for us considering we have above 50-50 % split of our views between the ERB templates and Angularjs.
More about this setup in the links below:
http://angular-rails.com/bootstrap.html
http://pete-hamilton.co.uk/2013/07/13/angularjs-and-rails-with-bower/
http://start.jcolemorrison.com/setting-up-an-angularjs-and-rails-4-1-project/
There are many advantages of separating out your api service (rails in this case) and your frontend components. As we do for ios/android apps, angular client can live on its own as a separate entity. It will be a static website that can be deployed on s3 or any static website host. It just needs to communicate with your api service. You could setup CORS to make it possible.
Some advantages of this workflow
You could use rails-api, which is a subset of rails application. If you are just going to use rails to build apis, it doesnt make sense to have all functionality that a complete rails app provides. Its lightweight, faster and inclined more towards building API first arch than a MVC arch.
You could use yeoman angular-generator to generate an angular app and make the most of grunt & bower to manage build (concat,uglify,cdnify etc) and dependencies (angular modules).
Deployments will become flexible. You won't need to depend on one to push the other.
If you ever plan to change your backend stack (eg rails to play/revel), you would not need to worry about your client components.
By splitting the development of the frontend and the Rails backend you could distribute the work over two development teams and keep the application as a whole very extensible.
There is also one downside to this approach.
By having the applications in two separate repositories, you can’t easily have a full integration test. So you will have to test the apps separately. You could mock your apis to test angular app.
We have been using this approach and would recommend others the same.
Less dependency & more productivity.

Resources