Search code examples
ruby-on-railsnode.jsreactjsherokucreate-react-app

Deploying Create-React-App with Rails API on Heroku


I'm having an issue getting my react /rails app to work on heroku. I've managed to get it deployed and the rails server starts but I'm not seeing my react app. I feel like I'm close but can't figure out what's missing.

So my process is currently to run npm run build locally from the client directory which builds a 'build' directory in client. I then commit the results of the build and push to Heroku with git push heroku master.

I then navigate to the heroku app in a browser where I'm only getting a blank white page which is an index file the I manually copied from the build dir to public. I'm not sure if the index file is correct but I just wanted to make sure i could hit something.

Ultimately, I would like to just push the repo and it automatically run the build. I've seen this mentioned various places but I always get a react-script does not exist error when I run npm run build on the server.

My configuration is as follows:

basic structure of app

/app - root of Rails app
/client - root of React app
/public - does display index page

root/client/package.json

{
    "name": "qc_react",
    "version": "0.1.0",
    "private": true,
    "devDependencies": {
        "react-scripts": "^0.8.4"
    },
    "dependencies": {
        "react": "^15.4.1",
        "react-dom": "^15.4.1",
        "react-router": "^3.0.0"
    },
    "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test --env=jsdom",
        "eject": "react-scripts eject"
    },
    "cacheDirectories": [
        "node_modules",
        "client/node_modules"
    ],
    "proxy": "${API_URL}:${PORT}/v1/"
}

root/package.json

{
  "name": "web",
  "version": "1.0.0",
  "description": "This repo contains a web application codebase. Read instructions on how to install.",
  "main": "index.js",
  "scripts": {
    "build": "cd client" # not sure what to put here but this gets me past build failure
  },
  "repository": {
    "type": "git",
    "url": "git+ssh://myrepo.git"
  },
  "author": "",
  "license": "ISC",
  "homepage": "https://myhomepage#readme"
}

Procfile

api: bundle exec puma -C config/puma.rb

Buildpacks

1. https://github.com/mars/create-react-app-buildpack.git
2. heroku/ruby

config/puma.rb

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3001
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

Solution

  • So I finally found the solution I was looking for. My code base has the following structure.

    app/
    client/
    public/
    ...
    

    I'm currently building my client solution as @yeasayer suggested above. After building and deploying my react project to the public folder in my rails api, I added the following to my routes:

    ... # api routes ...
    
    get '/*path', to: 'react#index'
    

    Then I created a react_controller and added the following contents:

    class ReactController < ActionController::Base
      def index
          render :file => 'public/index.html', :layout => false
      end
    end
    

    Now any routes not caught by the api routes, will render the react app. I'm not sure why others don't use this structure instead of using react_on_rails or some other plugin to achieve the same result. This setup is a lot simpler than dealing with these other solutions but I'd like to hear any thoughts on why this solution is not a good idea.