feat: add environment configuration files and update API base URL handling for production
This commit is contained in:
2
.env.development.template
Normal file
2
.env.development.template
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Development Environment Variables
|
||||||
|
VITE_API_BASE_URL=http://localhost:8000
|
||||||
3
.env.production.template
Normal file
3
.env.production.template
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Production Environment Variables
|
||||||
|
# In production with reverse proxy, we use relative URLs (same origin)
|
||||||
|
# No API base URL needed - the reverse proxy handles /api routing
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --port 8001",
|
"dev": "vite --port 8001",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
|
"build:production": "tsc -b && vite build --mode production",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useContext, useEffect, useState } from 'react'
|
||||||
import { ThemeProviderContext, type Theme } from '@/contexts/ThemeContext'
|
import { ThemeProviderContext, type Theme } from '@/contexts/ThemeContext'
|
||||||
|
|
||||||
type ThemeProviderProps = {
|
type ThemeProviderProps = {
|
||||||
@@ -49,3 +49,12 @@ export function ThemeProvider({
|
|||||||
</ThemeProviderContext.Provider>
|
</ThemeProviderContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useTheme = () => {
|
||||||
|
const context = useContext(ThemeProviderContext)
|
||||||
|
|
||||||
|
if (context === undefined)
|
||||||
|
throw new Error('useTheme must be used within a ThemeProvider')
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
ArrowRight,
|
ArrowRight,
|
||||||
ArrowRightToLine
|
ArrowRightToLine
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { playerService, type PlayerState, type PlayerMode } from '@/lib/api/services/player'
|
import { playerService, type PlayerState, type PlayerMode, type MessageResponse } from '@/lib/api/services/player'
|
||||||
import { filesService } from '@/lib/api/services/files'
|
import { filesService } from '@/lib/api/services/files'
|
||||||
import { playerEvents, PLAYER_EVENTS } from '@/lib/events'
|
import { playerEvents, PLAYER_EVENTS } from '@/lib/events'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
@@ -79,7 +79,7 @@ export function Player({ className }: PlayerProps) {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const executeAction = useCallback(async (action: () => Promise<void>, actionName: string) => {
|
const executeAction = useCallback(async (action: () => Promise<void | MessageResponse>, actionName: string) => {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
try {
|
try {
|
||||||
await action()
|
await action()
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ export function SocketProvider({ children }: SocketProviderProps) {
|
|||||||
const createSocket = useCallback(() => {
|
const createSocket = useCallback(() => {
|
||||||
if (!user) return null
|
if (!user) return null
|
||||||
|
|
||||||
const newSocket = io('http://localhost:8000', {
|
// Get socket URL - use relative URL in production with reverse proxy
|
||||||
|
const socketUrl = import.meta.env.PROD
|
||||||
|
? '' // Use relative URL in production (same origin as frontend)
|
||||||
|
: (import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000')
|
||||||
|
|
||||||
|
const newSocket = io(socketUrl, {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
transports: ['polling', 'websocket'],
|
transports: ['polling', 'websocket'],
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
|
|||||||
@@ -12,7 +12,15 @@ export class BaseApiClient implements ApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private buildURL(endpoint: string, params?: Record<string, string | number | boolean | undefined>): string {
|
private buildURL(endpoint: string, params?: Record<string, string | number | boolean | undefined>): string {
|
||||||
const url = new URL(endpoint, this.baseURL)
|
let url: URL
|
||||||
|
|
||||||
|
if (this.baseURL) {
|
||||||
|
// Full base URL provided
|
||||||
|
url = new URL(endpoint, this.baseURL)
|
||||||
|
} else {
|
||||||
|
// Use relative URL (for reverse proxy)
|
||||||
|
url = new URL(endpoint, window.location.origin)
|
||||||
|
}
|
||||||
|
|
||||||
if (params) {
|
if (params) {
|
||||||
Object.entries(params).forEach(([key, value]) => {
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
@@ -22,7 +30,7 @@ export class BaseApiClient implements ApiClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return url.toString()
|
return this.baseURL ? url.toString() : url.pathname + url.search
|
||||||
}
|
}
|
||||||
|
|
||||||
private async request<T>(
|
private async request<T>(
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
// API Configuration
|
// API Configuration
|
||||||
|
const getApiBaseUrl = () => {
|
||||||
|
// If VITE_API_BASE_URL is explicitly set to empty string, use relative URLs
|
||||||
|
if (import.meta.env.VITE_API_BASE_URL === '') {
|
||||||
|
return '' // Use relative URLs (reverse proxy handles routing)
|
||||||
|
}
|
||||||
|
// In production with reverse proxy, use relative URL (same origin)
|
||||||
|
if (import.meta.env.PROD) {
|
||||||
|
return '' // Use relative URLs in production (reverse proxy handles routing)
|
||||||
|
}
|
||||||
|
// Use environment variable in development, fallback to localhost
|
||||||
|
return import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000'
|
||||||
|
}
|
||||||
|
|
||||||
export const API_CONFIG = {
|
export const API_CONFIG = {
|
||||||
BASE_URL: 'http://localhost:8000',
|
BASE_URL: getApiBaseUrl(),
|
||||||
TIMEOUT: 30000, // 30 seconds
|
TIMEOUT: 30000, // 30 seconds
|
||||||
RETRY_ATTEMPTS: 1,
|
RETRY_ATTEMPTS: 1,
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { apiClient } from '../client'
|
|
||||||
import { API_CONFIG } from '../config'
|
import { API_CONFIG } from '../config'
|
||||||
|
|
||||||
export class FilesService {
|
export class FilesService {
|
||||||
|
|||||||
@@ -11,4 +11,11 @@ export default defineConfig({
|
|||||||
'@': path.resolve(__dirname, './src'),
|
'@': path.resolve(__dirname, './src'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Production build optimization
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
sourcemap: false, // Disable source maps in production for security
|
||||||
|
},
|
||||||
|
// For reverse proxy deployment, ensure assets are served from root
|
||||||
|
base: '/',
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user