How to Locally Develop the React Frontend with Vercel API Proxy in awesome‑gpt‑image‑2

The awesome‑gpt‑image‑2 repository uses a custom Vite plugin that intercepts /api/* requests during local development and dynamically imports serverless handlers from the api/ directory, eliminating the need for a separate backend or external proxy configuration.

The awesome‑gpt‑image‑2 project provides a single‑page React application that relies on Vercel serverless functions for its API layer. Developing this frontend locally presents a challenge: you need those API routes available without deploying to Vercel. According to the source code, the solution is a purpose‑built Vite plugin that runs exclusively during development and transparently proxies requests to local handler modules.

How the Vercel API Proxy Works

The local development system consists of three coordinated components that replicate Vercel's serverless runtime in your dev environment.

Component Purpose Location
Vite configuration Registers the custom plugin alongside React support vite.config.js
localVercelApi plugin Middleware that routes requests and provides response helpers scripts/vite-local-api.mjs
API handlers Node‑style modules exporting (req, res) functions api/ directory

The Route Loading System

At the heart of scripts/vite-local-api.mjs (lines 1‑14) sits a Map called routeLoaders that lazily maps URL paths to dynamic imports:

const routeLoaders = new Map([
  ['/api/community/config', () => import('../api/community/config.js')],
  ['/api/community/status', () => import('../api/community/status.js')],
  // … additional routes …
]);

This lazy‑loading design ensures that API handlers are only imported when first requested, keeping dev server startup fast.

Request Processing Pipeline

When a request hits the dev server, the middleware (lines 55‑99) executes a five‑stage pipeline:

  1. Parse the URL using new URL(req.url, 'http://127.0.0.1')
  2. Lookup the route in routeLoaders
  3. Short‑circuit unconfigured community routes — if Supabase is missing, /api/community/status returns a canned 200 response (lines 71‑80)
  4. Inject request helpers — attaches req.query, x-forwarded-proto header, and response methods (res.json, res.send, res.redirect)
  5. Execute the handler with await module.default(req, res)

Crucially, the plugin declares apply: 'serve', so it only activates during npm run dev. Production builds (npm run build) produce a static bundle without any proxy code—your API routes are handled by real Vercel serverless functions in deployment.

Setting Up Local Development with the Vercel API Proxy

Follow these steps to run the React frontend locally with full API support.

1. Clone and Install Dependencies

git clone https://github.com/freestylefly/awesome-gpt-image-2.git
cd awesome-gpt-image-2
npm install

This pulls React, Vite, the Supabase client, and development tooling.

2. Configure Environment Variables

Copy the example file and populate real values for your Supabase project and optional Google Analytics:

cp .env.example .env

# Edit .env to set:

#   VITE_SUPABASE_URL

#   SUPABASE_SERVICE_ROLE_KEY

#   VITE_GA_MEASUREMENT_ID

The SUPABASE_SERVICE_ROLE_KEY is required for community API functionality; without it, the proxy returns fallback responses.

3. Start the Vite Dev Server

npm run dev

The server initializes at http://localhost:5173. Vite loads vite.config.js, which imports and registers the localVercelApi plugin before the React plugin:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { localVercelApi } from './scripts/vite-local-api.mjs';

export default defineConfig({
  plugins: [localVercelApi(), react()],  // API proxy must precede React
  publicDir: 'data',
  build: {
    outDir: 'dist',
    sourcemap: false
  }
});

4. Verify the Proxy is Active

Open your browser console and test a community endpoint:

fetch('/api/community/status')
  .then(r => r.json())
  .then(console.log);

Without Supabase configured, expect this response defined in the plugin's fallback logic:

{
  "ok": true,
  "authenticated": false,
  "eligible": false,
  "qrReady": false,
  "paymentEnabled": false,
  "order": null,
  "localPreview": true
}

This confirms the middleware is intercepting requests and routing them correctly.

5. Develop Your React Components

Edit files under src/ (e.g., src/main.jsx). The dev server provides hot module replacement, and all /api/* calls are proxied transparently. No additional proxy configuration in vite.config.js is needed—the plugin handles routing internally.

6. Test Production Build (Optional)

When ready to validate the static output:

npm run build
npm run preview

The preview server serves dist/ without the API proxy. API routes are expected to be provided by Vercel's serverless infrastructure in actual deployment.

Inside the Vite Plugin Implementation

The localVercelApi function in scripts/vite-local-api.mjs demonstrates several techniques for replicating serverless runtime behavior:

export function localVercelApi() {
  return {
    name: 'local-vercel-community-api',
    apply: 'serve',  // Dev-only: excluded from production builds
    
    configureServer(server) {
      server.middlewares.use(async (req, res, next) => {
        const requestUrl = new URL(req.url || '/', 'http://127.0.0.1');
        const routeLoader = routeLoaders.get(requestUrl.pathname);
        const isCommunityApi = requestUrl.pathname.startsWith('/api/community/')
          || requestUrl.pathname.startsWith('/api/admin/community/');

        // 404 for unknown community routes
        if (!routeLoader) {
          if (isCommunityApi) {
            return sendJson(res, 404, { ok: false, error: 'NOT_FOUND' });
          }
          return next();  // Let Vite handle static assets
        }

        // Supabase-less fallback for status check
        if (requestUrl.pathname === '/api/community/status' 
            && !isSupabaseServerConfigured()) {
          return sendJson(res, 200, { /* fallback status */ });
        }

        // Populate Vercel-compatible request/response objects
        req.query = Object.fromEntries(requestUrl.searchParams.entries());
        attachVercelResponseHelpers(res);
        
        // Invoke the handler
        const module = await routeLoader();
        await module.default(req, res);
      });
    }
  };
}

Key implementation details:

  • attachVercelResponseHelpers(res) (lines 83‑52) polyfills res.json(), res.send(), and res.redirect() to match Vercel's response API
  • Dynamic imports avoid loading all handlers upfront—only accessed routes are evaluated
  • Environment detection via isSupabaseServerConfigured() enables graceful degradation when credentials are missing

Calling API Routes from React

Any component can use standard fetch against /api/* paths. From src/main.jsx or your own components:

async function loadCommunityStatus() {
  const resp = await fetch('/api/community/status');
  if (!resp.ok) throw new Error(`API error: ${resp.status}`);
  const data = await resp.json();
  return data;
}

// Usage in a component
useEffect(() => {
  loadCommunityStatus().then(setStatus);
}, []);

The browser sees these as same‑origin requests because the Vite dev server handles them internally—no CORS configuration required.

Key Files Reference

File Role
vite.config.js Vite configuration with localVercelApi() plugin registration
scripts/vite-local-api.mjs Middleware implementation for local API proxy
api/community/status.js Example serverless handler; loaded dynamically in dev
api/community/config.js Configuration endpoint handler
src/main.jsx React entry point making API calls
.env.example Required environment variable documentation
vercel.json Production Vercel configuration (reference only)

Summary

  • The localVercelApi Vite plugin enables local development of the awesome‑gpt‑image‑2 React frontend with full API functionality—no external proxy or deployed backend required.
  • Dynamic route loading from scripts/vite-local-api.mjs maps /api/* paths to local handlers in the api/ directory using lazy import() calls.
  • Dev‑only activation via apply: 'serve' ensures zero impact on production builds; npm run build outputs a static bundle ready for Vercel's real serverless functions.
  • Zero additional configuration is needed beyond npm install, environment variables, and npm run dev—the plugin handles all request routing and response helper injection automatically.

Frequently Asked Questions

Do I need to deploy the API to Vercel before I can develop the frontend?

No. The localVercelApi plugin in scripts/vite-local-api.mjs intercepts all /api/* requests during npm run dev and executes the corresponding handler files from your local api/ directory. You only deploy to Vercel when you're ready for production.

What happens if I don't configure Supabase environment variables?

The plugin detects missing Supabase configuration via isSupabaseServerConfigured() and returns fallback responses for community endpoints. For example, /api/community/status returns a 200 with localPreview: true and authenticated: false, allowing UI development to proceed without a backend database.

Can I add new API routes for local development?

Yes. Create a new handler file in api/ exporting a default (req, res) function, then register its path in routeLoaders within scripts/vite-local-api.mjs. The dynamic import system will pick it up on the next request without restarting the dev server.

Why does the production build exclude the proxy?

The plugin specifies apply: 'serve', which restricts it to Vite's development server only. The npm run build command generates a static dist/ folder containing just the React application. In production, Vercel's actual serverless infrastructure—configured via vercel.json—handles API routes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →