Search code examples
node.jsazureazure-web-app-servicenode-modulesazure-appservice

How to build and deploy to Azure App Service an app with Flask as backend and Node.js as front end


I have an app that works locally and now I want to deploy on Azure App Service using the Visual studio extension.

I have a root folder that contains two folders:

  1. one for the python backend, that contains the files to start a Flask server that is only used to handle the requests for pages
  2. one folder for the frontend that contains all the files that must be built and then copied into the backend folder after the npm run build command is run.

More in detail:

  1. in the backend folder I have app.py , requirements.txt

  2. in the frontend folder I have src/ , public/ , package.json , package-lock.json , vite.config.js

  3. In the root folder I have .deployment ,startup.sh

This is the .deployment file

[config]
SCM_DO_BUILD_DURING_DEPLOYMENT=1
command = ./startup.sh

This is the startup.sh file

cd frontend
ls .
npm install
echo "Done installing"
npm run build # the build command already copies files in backend
cd ../backend
pip install -r requirements.txt
gunicorn app:app --bind=0.0.0.0:8000

The build script is specified in this way: "build": "vite build && ncp dist ../backend/static",

This is the output I get when deploying, from which I understand that the npm install doesn't run to completion.

4:18:41 PM TestOD: eslint.config.js
4:18:41 PM TestOD: index.html
4:18:41 PM TestOD: package-lock.json
4:18:41 PM TestOD: package.json
4:18:41 PM TestOD: public
4:18:41 PM TestOD: src
4:18:41 PM TestOD: vite.config.js
4:18:48 PM: Deployment to "TestOD" completed.

This is the app.py file

from flask import Flask, render_template, send_from_directory
import os
import sys

build_folder = 'static'

if getattr(sys, 'frozen', False):    
    template_dir = os.path.join(sys._MEIPASS, build_folder)
else:    
    ROOT_PATH = os.path.abspath(os.path.dirname(__file__))    
    template_dir = os.path.join(ROOT_PATH, build_folder)
 

app = Flask(__name__, static_folder=os.path.join(template_dir, 'assets'), template_folder=template_dir)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/<path:path>')
def catch_all(path):
    return render_template('index.html')

if __name__ == '__main__':
   app.run()

What can I do to find out the cause? Is the structure correct? Should I specify something else in the .deployment file? I have no other idea on how to proceed

  • I have already tried looking at all the logs in Azure but nothing helped.
  • I have tried deploying the app by running manually the installation and building of all the files required by python to run the code, and in that case the app is loaded just fine.
  • I have noticed that App Service expects "lockfileVersion": 1 in package-lock.json, even if current version of npm output "lockfileVersion": 3. I managed to downgrade it using npx [email protected] i --save --package-lock-only from this answer, but I am not sure whether that's a good idea

Solution

  • I created a sample application with a Python backend and a Node.js frontend and successfully deployed it to Azure using the VS Code extension.

    Below is my complete app. py code.

    app. py:

    from flask import Flask, render_template
    import os
    build_folder = 'static'
    app = Flask(__name__, static_folder=os.path.join(build_folder, 'assets'), template_folder=build_folder)
    @app.route('/')
    def index():
        return render_template('index.html')
    @app.route('/<path:path>')
    def catch_all(path):
        return render_template('index.html')
    if __name__ == '__main__':
        app.run()
    

    I added below lines to vite.config.ts file.

    build: {
        outDir: "dist", 
        assetsDir: "assets" 
      }
    

    vite.config.ts:

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    export default defineConfig({
      plugins: [react()],
      build: {
        outDir: "dist", 
        assetsDir: "assets" 
      }
    })
    

    I added the below build script to package.json file.

    "scripts": {
    "dev": "vite",
    "build": "vite build && ncp dist ../backend/static",
    "lint": "eslint .",
    "preview": "vite preview"
    }
    

    Before deploying to Azure Web App, make sure to build the frontend application so that the static files are stored in the backend folder. Then, deploy only the Python backend folder to Azure App Service.

    To build frontend I used below command.

    npm run bulid
    

    I followed the below steps to deploy the app to Azure.

    enter image description here

    enter image description here

    Azure Output:

    enter image description here