angularflaskheroku

Deploying Flask / Angular app _from the same repository_ to Heroku


I have an existing app written in Flask, deployed to Heroku, It works great, but I decided to convert it to an Angular frontend, using Flask just for the API. This also works great locally, but I'm almost done and I'd like deploy it to Heroku from the same repository. This site is an internal set of tools and is SUPER low traffic...think 20-40 hits a day MAX.

This is the current file system structure:

├── Procfile
├── README.md
├── backend
│   ├── app.py
│   ├── requirements.txt
│   ├── static **(will not be used by Flask)**
│   └── templates **(will not be used by Flask)**
├── frontend
│   ├── angular.json
│   ├── dist
│   │   ├── mmscripts
│   │   │   ├── 3rdpartylicenses.txt
│   │   │   └── browser
│   │   │   │   ├── favicon.ico
│   │   │   │   ├── index.html
│   │   │   │   ├── main-HX6HQ3LL.js
│   │   │   │   ├── polyfills-S3BTP7ME.js
│   │   │   │   └── styles-HCXVZOOP.css
│   ├── package-lock.json
│   ├── package.json
│   ├── src
│   │   ├── app
│   │   │   ├── env.ts
│   │   ├── assets
│   │   ├── favicon.ico
│   │   ├── index.html
│   │   ├── main.ts
│   │   └── styles.scss
│   ├── tsconfig.app.json
│   ├── tsconfig.json
│   └── tsconfig.spec.json
└── runtime.txt

At the moment I cd into backend and run the Flask app: FLASK_ENV=development flask run

Then in a separate shell I cd into frontend and run ng serve. I have Flask-Cors installed in the Flask app so that Angular can access the API, then in frontend/src/app/env.ts I've got this constant:

export const API_URL = 'http://localhost:5000/api';

Here's some versioning:

Angular 17
Flask 3
Flask-Cors 4
Heroku stack is 22

Procfile:

web: gunicorn app:app

runtime.txt

python-3.9.19

I don't mind rearranging the file system if need be. I just used this particular setup because it seemed to make things easier from an organizational standpoint.


Solution

  • I was able to get this working almost exactly like I was hoping.

    For anyone coming behind me, here's how I accomplished it.

    1. Create backend and a frontend directories.
      1. Flask code goes in the backend directory as shown above.
      2. Angular code goes in the frontend directory as shown above.
    2. In the root of the project, create a Procfile which contains the below code.
      1. web: gunicorn --chdir ./backend app:app
      2. In my case I'm using gunicorn, if you're using another server, the approach might be different.
    3. In the frontend directory, prior to deploying to Heroku, run the following command:
      1. ng build --configuration production
      2. A dist folder should either be created, or updated, with your minimized Angular code.

    In order to allow Flask to serve the proper files, I also had to make changes to my app.py file as follows:

    from flask import (
        Flask,
        send_from_directory,
    )
    
    app = Flask(__name__, static_folder='../frontend/dist/<my Angular app name>/browser/', static_url_path='')
    
    @app.errorhandler(404)
    @app.route('/',defaults={"e": ""})
    def index(e):
        return send_from_directory(app.static_folder, 'index.html')
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=81)