Integrating Vite with Flask for Production
Tags: vite, flask, production, supabase
Published: 2024-01-15 20:04:58

---
title: Integrating Vite with Flask for Production
published: true
description: Configuring Vite to work with Flask and overcoming challenges to production, a technical post.
tags: #Vite, #Flask, #Production, #Supabase  
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xy3806ab23rv0vdlxp3i.png
#Use a ratio of 100:42 for best results.
#published_at: 2024-01-15 19:36 +0000
---


In this post, we'll explore how to configure Vite and Flask to run seamlessly together in a production environment. This setup is ideal for developers looking to leverage the speed of Vite for frontend development with the power and simplicity of Flask for the backend.

## Prerequisites
Before we dive into the configurations, let's assume you have the basic project structure set up. This includes a standard Flask application and a Vite-powered React frontend.

## Configuring Vite for Development
We start by setting up our **vite.config.js** file for the development environment. The configuration ensures that Vite serves our React frontend and proxies API requests to our Flask backend.

Here's the **vite.config.js** file for development:

```javascript

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
  base: './',
  plugins: [react()],
  build: {
    assetsDir: 'static',
  },
  server: {
    port: 3000,
    cors: true,
    proxy: {
      "/api": {
        target: "http://127.0.0.1:5555/",
        changeOrigin: true,
        secure: false,
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },
});
```
Key Points:

* The base is set to './' to ensure that the built paths are relative.
* assetsDir is configured as 'static', aligning with Flask's static file serving convention.
* The development server runs on port 3000.
* CORS is enabled for development.
* A proxy is set up for requests starting with /api, redirecting them to the Flask server running on http://127.0.0.1:5555/.
##Adapting Configuration for Production
For production, we simplify the configuration by removing the development server settings. Since Flask will serve our static files in production, we don't need Vite's development server and its proxy settings.

In the production version of **vite.config.js**, simply omit the **server** object:

```javascript
// ... rest of the configuration
build: {
  assetsDir: 'static',
},
// No server object for production
```
In the upcoming sections, we'll dive deeper into how to configure Flask to serve the Vite-built assets and ensure that both Flask and Vite work harmoniously in a production setting.

##Backend Configuration in Flask
Moving to the backend, let's talk about the Flask configuration. While many developers prefer to place the Flask app initialization in **app.py**, I choose to place it in **config.py**. This keeps all configurations centralized, making the codebase cleaner and easier to maintain.

Furthermore, for production, special attention is given to how the **static_folder** and **template_folder** are set up, especially since we're integrating with a Vite frontend. Here's what the **config.py** file looks like in production:

```python

import os
from dotenv import load_dotenv

load_dotenv()
from flask import Flask
from flask_bcrypt import Bcrypt
from flask_migrate import Migrate
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from flask_cors import CORS

app = Flask(
  __name__, 
  static_folder='../client/dist/static',
  template_folder='../client/dist'
)

app.secret_key = os.getenv('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('SUPABASE_URI')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config
['SESSION_COOKIE_NAME'] = 'id'
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'None'
app.json.compact = False

metadata = MetaData(naming_convention={
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
})
db = SQLAlchemy(metadata=metadata)
migrate = Migrate(app, db)
db.init_app(app)
bcrypt = Bcrypt(app)
api = Api(app)
CORS(app)
```
For the production setup in **app.py**, it's essential to add a catch-all route to handle redirects for single-page applications:

```python

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    return render_template("index.html")

if __name__ == '__main__':
    app.run()
```
This setup ensures that all routes are correctly redirected to the **index.html** file, a common requirement for single-page applications in production.

Building and Starting the App
When deploying to a platform like Render or similar, ensure you use Gunicorn for the backend. Assuming your project is structured into two separate folders (**client** for the frontend and **server** for the backend) and your Pipenv dependencies are transferred into a **requirements.txt** file, (which can be done via command pip freeze > requirements.txt) your build command would look like this:

```bash
pip install -r requirements.txt && npm install --prefix client && npm run build --prefix client
```
And the start command for Gunicorn would be:
```bash
gunicorn --chdir server app:app
```
##Overcoming Limitations: Serving Images from the Public Folder
A limitation I encountered with this setup involved serving images from the **public** folder. Vite handles this well in development, but Flask doesn't automatically serve these files in production. To overcome this, I utilized Supabase's storage feature, which provided a more scalable and professional solution.

##The Solution: 
**Supabase Storage** and Server-Side Rendering
Images are uploaded to [Supabase](https://supabase.io/), offering a scalable and efficient solution. The Flask backend fetches image URLs server-side, and the frontend, served by Vite, displays the images. This method enhanced scalability and performance.

Implementation Overview
1. **Uploading Images to Supabase Storage:** Secure and structured storage solution.

2.**Fetching Image URLs Server-Side:** Flask backend dynamically retrieves image URLs.

3.**Rendering Images in the Frontend:** Vite-served frontend displays images using these URLs.

##Conclusion

This challenge led to discovering a robust solution. Using Supabase Storage for image handling not only addressed the initial issue but also added significant benefits in scalability and performance. This approach, combining Flask's server-side capabilities with Supabase's storage, resulted in a more professional and scalable application.

Combining Vite and Flask for a production environment offers an efficient and modern web development experience. By addressing and overcoming specific challenges, the integration of these two powerful tools can lead to the creation of high-performance, scalable web applications.