Files
csgowtf/docs/CORS_PROXY.md
vikingowl 274f5b3b53 fix: Configure Vite proxy to eliminate CORS issues in development
Implemented a comprehensive CORS proxy solution that works with both
local and remote backends during development.

## Changes

### Vite Configuration (vite.config.ts)
- Use loadEnv() to properly read VITE_API_BASE_URL from .env
- Configure proxy to forward /api/* requests to backend
- Add detailed logging for proxy requests and responses
- Support changeOrigin, rewrite, secure=false, and websockets

### API Client (src/lib/api/client.ts)
- In development: Always use /api prefix (proxied)
- In production: Use direct VITE_API_BASE_URL
- Add console logging to show proxy configuration in dev mode
- Automatic detection of environment (DEV vs PROD)

### Error Handling (route loaders)
- Fix console.error() calls that caused TypeError with circular refs
- Use error.message instead of logging full error objects
- Affects: +page.ts, matches/+page.ts

### Documentation
- docs/LOCAL_DEVELOPMENT.md: Complete rewrite with proxy explanation
  - Quick start guide for both production API and local backend
  - Detailed proxy flow diagrams
  - Comprehensive troubleshooting section
  - Clear examples and logs

- docs/CORS_PROXY.md: Technical deep-dive on proxy implementation
  - How the proxy works internally
  - Configuration options explained
  - Testing procedures
  - Common issues and solutions

- .env.example: Updated with proxy documentation

## How It Works

Development Flow:
1. Frontend makes request: /api/matches
2. Vite proxy intercepts and forwards to: ${VITE_API_BASE_URL}/matches
3. Backend responds (no CORS headers needed)
4. Proxy returns response to frontend (same-origin)

Production Flow:
1. Frontend makes request directly to: https://api.csgow.tf/matches
2. Backend responds with CORS headers
3. Browser allows request (CORS enabled on backend)

## Benefits
 No CORS errors in development
 Works with local backend (localhost:8000)
 Works with remote backend (api.csgow.tf)
 Simple configuration (just set VITE_API_BASE_URL)
 Detailed logging for debugging
 Production build unaffected (direct requests)

## Testing
Verified with production API:
- curl https://api.csgow.tf/matches ✓
- Dev server proxy logs show successful forwarding ✓
- Browser Network tab shows /api/* requests ✓
- No CORS errors in console ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 21:34:26 +01:00

6.2 KiB

CORS Proxy Configuration

This document explains how the CORS proxy works in the CS2.WTF frontend.

Problem: CORS in Development

When developing a frontend that talks to an API on a different origin, browsers enforce CORS (Cross-Origin Resource Sharing) policies. This causes errors like:

Access to fetch at 'https://api.csgow.tf/matches' from origin 'http://localhost:5173'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.

Solution: Vite Development Proxy

The Vite dev server includes a built-in proxy that solves this problem by making all API requests appear same-origin.

Configuration

File: vite.config.ts

import { loadEnv } from 'vite';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  const apiBaseUrl = env.VITE_API_BASE_URL || 'http://localhost:8000';

  return {
    server: {
      proxy: {
        '/api': {
          target: apiBaseUrl,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
          secure: false,
          ws: true
        }
      }
    }
  };
});

How It Works

  1. API Client (in development) makes requests to /api/*:

    // src/lib/api/client.ts
    const API_BASE_URL = import.meta.env.DEV ? '/api' : VITE_API_BASE_URL;
    
  2. Vite Proxy intercepts requests to /api/* and forwards them:

    Browser Request:  GET http://localhost:5173/api/matches?limit=6
                            ↓
    Vite Proxy:       Intercepts /api/* requests
                            ↓
    Backend Request:  GET https://api.csgow.tf/matches?limit=6
                            ↓
    Response:         ← Returns data through proxy
                            ↓
    Browser:          ← Receives response (appears same-origin)
    
  3. Browser sees same-origin request - no CORS error!

Configuration Options

Option Value Purpose
target env.VITE_API_BASE_URL Where to forward requests
changeOrigin true Updates Origin header to match target
rewrite Remove /api prefix Maps /api/matches/matches
secure false Allow self-signed certificates
ws true Enable WebSocket proxying

Environment Variables

.env:

# Proxy will forward /api/* to this URL
VITE_API_BASE_URL=https://api.csgow.tf

# Or use local backend
# VITE_API_BASE_URL=http://localhost:8000

Logging

The proxy logs all requests for debugging:

[Vite Config] API Proxy target: https://api.csgow.tf
[Proxy] GET /api/matches?limit=6 -> https://api.csgow.tf/matches?limit=6
[Proxy ✓] GET /api/matches?limit=6 -> 200
[Proxy] GET /api/match/123 -> https://api.csgow.tf/match/123
[Proxy ✓] GET /api/match/123 -> 200

Error logging:

[Proxy Error] ECONNREFUSED
[Proxy Error] Make sure backend is running at: http://localhost:8000

API Client Configuration

File: src/lib/api/client.ts

const getAPIBaseURL = (): string => {
  // In production builds, use the configured URL directly
  if (import.meta.env.PROD) {
    return import.meta.env?.VITE_API_BASE_URL || 'https://api.csgow.tf';
  }

  // In development mode, ALWAYS use the Vite proxy to avoid CORS issues
  // The proxy will forward /api requests to VITE_API_BASE_URL
  return '/api';
};

This ensures:

  • Development: Always uses /api (proxy handles CORS)
  • Production: Uses direct URL (backend has CORS enabled)

Testing the Proxy

1. Check Vite Config Loads Environment

Start dev server and look for:

npm run dev

# Should show:
[Vite Config] API Proxy target: https://api.csgow.tf

2. Check API Client Configuration

Open browser console, look for:

[API Client] Development mode - using Vite proxy
[API Client] Frontend requests: /api/*
[API Client] Proxy target: https://api.csgow.tf

3. Check Network Requests

Open DevTools → Network tab:

  • Requests should go to /api/* (not full URL)
  • Response should be 200 OK
  • No CORS errors in console

4. Check Proxy Logs

Terminal should show:

[Proxy] GET /api/matches -> https://api.csgow.tf/matches
[Proxy ✓] GET /api/matches -> 200

Common Issues

Issue 1: Proxy Not Loading .env

Symptom: Proxy uses default http://localhost:8000 instead of .env value

Cause: vite.config.ts not loading environment variables

Fix: Use loadEnv() in config:

import { loadEnv } from 'vite';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  const apiBaseUrl = env.VITE_API_BASE_URL || 'http://localhost:8000';
  // ...
});

Issue 2: Still Getting CORS Errors

Symptom: Browser console shows CORS errors

Possible Causes:

  1. API client not using /api prefix in development
  2. Request bypassing proxy somehow
  3. Running production build instead of dev server

Fix:

  1. Check API client logs show: Development mode - using Vite proxy
  2. Verify Network tab shows requests to /api/*
  3. Run npm run dev (not npm run preview)

Issue 3: Connection Refused

Symptom: [Proxy Error] ECONNREFUSED

Cause: Backend is not running at the configured URL

Fix:

  • If using local backend: Start csgowtfd on port 8000
  • If using production API: Check VITE_API_BASE_URL=https://api.csgow.tf

Production Build

In production, the proxy is not used. The frontend makes direct requests to the backend:

// Production build
const API_BASE_URL = 'https://api.csgow.tf';

// Direct request (no proxy)
fetch('https://api.csgow.tf/matches');

The production API must have CORS enabled:

Access-Control-Allow-Origin: https://cs2.wtf
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

Summary

Environment Frontend URL API Requests CORS
Development http://localhost:5173 /api/* → Proxy → Backend Proxy handles
Production https://cs2.wtf Direct to backend Backend CORS

The proxy is a development-only feature that makes local development smooth and eliminates CORS headaches.