- Flask Image Optimizer runs locally (e.g.,
http://127.0.0.1:5000). - React app runs locally (e.g.,
http://localhost:5173).
1) Run the Flask app
Activate your Python virtual environment and start Flask:http://127.0.0.1:5000.
2) Handle CORS (Cross-Origin Resource Sharing)
When the React dev server uses a different origin (for examplehttp://localhost:5173), the browser will block cross-origin fetch requests unless the backend allows that origin.
Install Flask-CORS in your virtual environment:
__init__.py or wherever you create the app). The following example allows requests only from your dev frontend origin and restricts methods and headers used by the client:
Allowing only specific origins is safer than
CORS(app) which opens all origins. In production, set the allowed origin(s) via environment variables so you can update them without changing code.3) Verify the endpoint path
Confirm your React client posts to the exact route your Flask app expects. If your Flask route is/upload, make sure the client sends the request to http://127.0.0.1:5000/upload. Posting to the wrong path (e.g., /) results in a 404.
Quick manual test using curl or Postman:
4) React: POST image and handle binary (Blob) response
Below is an exampleApp.jsx demonstrating best practices:
- Build
FormDatawith the selected file and other form values (e.g., quality). - Send the
FormDatausing fetch to the Flask/uploadendpoint. - Parse the response as a
Blobbecause Flask returns raw image bytes. - Use
URL.createObjectURL(blob)to display the optimized image in the browser. - Track and display original and optimized file sizes, and revoke object URLs to prevent memory leaks.
App.jsx with this pattern.
- Use
response.blob()because the Flask backend returns binary image bytes. Parsing as JSON will cause a SyntaxError. - Display the returned image by creating an object URL with
URL.createObjectURL(blob). - Use
file.sizefor the original file andblob.sizefor the optimized result. - Revoke object URLs in
useEffectcleanup to avoid memory leaks.
5) Backend: return binary image bytes (not JSON)
Ensure the Flask endpoint acceptsmultipart/form-data, processes the image (for example, using Pillow), and returns raw image bytes with the correct Content-Type header (e.g., image/jpeg or image/png). If you intend the client to use the response as an image, return the binary stream — do not wrap the image bytes in JSON.
Example minimal route (conceptual):
- Set the correct mimetype to match the returned bytes.
- If you need to support multiple output formats, choose the format dynamically and set mimetype accordingly.
- When debugging, verify the response headers and payload with Postman or curl to confirm raw bytes are returned.
6) Avoid hard-coding the API URL
Do not embed the API base URL in application code for production. Use environment variables or a configuration approach.Store the backend API URL in an environment variable (e.g.,
VITE_API_URL with Vite) and reference it in the frontend. This simplifies switching between development, staging, and production.- Create
.env(not committed) withVITE_API_URL=http://127.0.0.1:5000. - Use it in React:
const api = import.meta.env.VITE_API_URL || 'http://127.0.0.1:5000';
Quick troubleshooting table
Final checklist before deployment
- Start and test the Flask server (
flask run) and verify/uploadwith Postman or curl. - Start React dev server (
npm run dev) and test the UI upload flow. - Replace all local URLs with environment-managed values for production.
- Lock down CORS to only the production frontend origin(s).
- Keep documentation up-to-date with any structural or endpoint changes.
