Mr.J
Mr.J

Reputation: 51

why can't i deploy react flask app on heroku?

Newbie here again asking another question. This time is more about Heroku itself. So, I have a project built with react for the main front-end and Flask as an Internal API. So far, Flask is deployed on Heroku fine, endpoints working as expected. However, i am having a difficult time on deploying the React files on Heroku with the FLASK server deployed already.. Googled, came across some good resources but no luck on implementing any idea or how to go about it. Main issue is how can i tell heroku to npm run build or start react files? or even to deploy properly this application...

More in depth, how would i let Heroku know which react files to use if front-end (react.js) directory has .gitignore which has the build folder ignored?

note: no need to answer directly, can post any useful resource that can guide me to completely deploy project for learning purposes.

project folder structure

back-end/
          .env
          files required to run server locally

front-end/
          - build
          - public
          - src
app.py

Procfile

requirements.txt

Procfile

web: gunicorn app:app

ap.py

import os
import tweepy
import json
from flask import Flask, jsonify

app = Flask(__name__, static_folder='./front-end/build/', static_url_path='/')

consumer_key = os.environ.get('CONSUMER_KEY')
consumer_token = os.environ.get('CONSUMER_SECRET')
access_token_key = os.environ.get('ACCESS_TOKEN')
access_token_key_secret = os.environ.get('ACCESS_TOKEN_SECRET')

auth = tweepy.OAuthHandler(consumer_key, consumer_token)
auth.set_access_token(access_token_key, access_token_key_secret)
api = tweepy.API(auth)


@app.route('/', methods=['GET'])
def home():
    return app.send_static_file('index.html')


@app.errorhandler(404)
def not_found(e):
    return app.send_static_file('index.html')


@app.route('/randomtweets', methods=['GET'])
def random_tweets():
    andys = api.get_user(screen_name='andysterks')
    bmws = api.get_user(screen_name='BMW')
    gtrs = api.get_user(screen_name='JustGTRs')

    andys_info = api.user_timeline(screen_name='andysterks')
    bmws_info = api.user_timeline(screen_name='BMW')
    gtrs_info = api.user_timeline(screen_name='JustGTRs')

    users_info = {
        "name": {
            "andy": andys.name,
            "gtr": gtrs.name,
            "bmw": bmws.name
        },
        "username": {
            "andys": andys.screen_name,
            "gtrs": gtrs.screen_name,
            "bmws": bmws.screen_name
        },

        "profile_image": {
            "andys": andys.profile_image_url_https,
            "gtrs": gtrs.profile_image_url_https,
            "bmws": bmws.profile_image_url_https
        }
    }

    return jsonify(users_info)


@app.route('/andy', methods=["GET"])
def andy_request():
    andy_get_tweets = api.user_timeline(screen_name="andysterks", count=5)

    andys_tweets_list = []

    for tweets in andy_get_tweets:
        andys_tweets_list.append(tweets.text)

    return jsonify({"andys_tweets": andys_tweets_list})


@app.route('/bmw', methods=["GET"])
def bmw_request():
    bmw_get_tweets = api.user_timeline(screen_name="BMW", count=5)

    bmws_tweets_list = []

    for tweets in bmw_get_tweets:
        bmws_tweets_list.append(tweets.text)

    return jsonify({"bmws_tweets": bmws_tweets_list})


@app.route('/gtr', methods=["GET"])
def gtr_request():
    gtr_get_tweets = api.user_timeline(screen_name="JustGTRs", count=5)

    gtrs_tweets_list = []

    for tweets in gtr_get_tweets:
        gtrs_tweets_list.append(tweets.text)

    return jsonify({"gtrs_tweets": gtrs_tweets_list})


@app.route('/search/<string:name>', methods=['GET'])
def search_user_request(name):
    user = api.get_user(screen_name=name)
    user_tweets = api.user_timeline(screen_name=name, count=5)

    searched_user_tweets = []

    for tweets in user_tweets:
        searched_user_tweets.append(tweets.text)

    user_data = {
        "name": user.name,
        "username": user.screen_name,
        "followers_count": user.followers_count,
        "following": user.friends_count,
        "tweets": searched_user_tweets,
        "profile_image": user.profile_image_url_https
    }

    return jsonify({'user_info': user_data})


if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=False, port=5000)


package.json

{
  "name": "front-end",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.6",
    "@testing-library/react": "^11.2.2",
    "@testing-library/user-event": "^12.2.2",
    "axios": "^0.21.0",
    "react": "^17.0.1",
    "react-bootstrap": "^1.4.0",
    "react-dom": "^17.0.1",
    "react-router": "^5.2.0",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.1",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "start-flask": "cd ../back-end && flask run",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "proxy": "http://127.0.0.1:5000/"
}

Upvotes: 1

Views: 433

Answers (1)

Beppe C
Beppe C

Reputation: 13883

The application needs to bind to the port provided by Heroky via the PORT environment variable

app.run(host='0.0.0.0', debug=False, port=int(os.environ.get("PORT", 5000)))

On you local it will use the default 5000, but on Heroku it will bind to PORT

Upvotes: 1

Related Questions