# Build stage FROM node:18-alpine AS builder # Install build dependencies for native modules (bcrypt, etc.) RUN apk add --no-cache python3 make g++ libc6-compat WORKDIR /app # Copy package files first for better Docker layer caching COPY package*.json ./ # Install dependencies with proper npm cache handling RUN npm ci --only=production=false --silent # Copy source code COPY . . # Set build-time environment variables ARG VITE_APP_NAME="ScriptShare" ARG VITE_APP_URL="https://scriptshare.example.com" ARG VITE_ANALYTICS_ENABLED="false" # Export as environment variables for Vite build ENV VITE_APP_NAME=$VITE_APP_NAME ENV VITE_APP_URL=$VITE_APP_URL ENV VITE_ANALYTICS_ENABLED=$VITE_ANALYTICS_ENABLED # Remove problematic packages from package.json to prevent them from being bundled RUN sed -i '/"mysql2"/d' package.json RUN sed -i '/"drizzle-orm"/d' package.json RUN sed -i '/"bcrypt"/d' package.json RUN sed -i '/"jsonwebtoken"/d' package.json RUN sed -i '/"@types\/bcrypt"/d' package.json RUN sed -i '/"@types\/jsonwebtoken"/d' package.json RUN sed -i '/"nanoid"/d' package.json # Reinstall dependencies without server packages RUN npm install # Remove problematic server-side API files for frontend-only build RUN rm -rf src/lib/api || true RUN rm -rf src/lib/db || true # Create mock API layer for frontend demo RUN mkdir -p src/lib/api src/lib/db # Create mock database files RUN echo "export const db = {};" > src/lib/db/index.ts RUN echo "export const users = {}; export const scripts = {}; export const ratings = {}; export const scriptVersions = {}; export const scriptAnalytics = {}; export const scriptCollections = {}; export const collectionScripts = {};" > src/lib/db/schema.ts # Create comprehensive mock API files using printf for reliable multiline content # Mock API index with proper types RUN printf 'export const generateId = () => Math.random().toString(36).substr(2, 9);\nexport class ApiError extends Error {\n constructor(message: string, public status: number) {\n super(message);\n this.status = status;\n }\n}' > src/lib/api/index.ts # Mock auth API with complete interface RUN printf 'export const authApi = {\n login: async (data: any) => ({ token: "demo", user: { id: "1", username: "demo" } }),\n register: async (data: any) => ({ token: "demo", user: { id: "1", username: "demo" } }),\n changePassword: async (data: any) => ({}),\n refreshToken: async () => ({ token: "demo" })\n};' > src/lib/api/auth.ts # Mock scripts API with all required methods RUN printf 'export interface ScriptFilters {\n search?: string;\n categories?: string[];\n compatibleOs?: string[];\n sortBy?: string;\n limit?: number;\n isApproved?: boolean;\n}\nexport interface UpdateScriptData {\n name?: string;\n description?: string;\n content?: string;\n}\nexport const scriptsApi = {\n getScripts: async (filters?: ScriptFilters) => ({ scripts: [], total: 0 }),\n getScriptById: async (id: string) => null,\n getPopularScripts: async () => [],\n getRecentScripts: async () => [],\n createScript: async (data: any) => ({ id: "mock" }),\n updateScript: async (id: string, data: UpdateScriptData, userId: string) => ({ id }),\n deleteScript: async (id: string, userId: string) => ({}),\n moderateScript: async (id: string, isApproved: boolean, moderatorId: string) => ({ id, isApproved }),\n incrementViewCount: async (id: string) => ({}),\n incrementDownloadCount: async (id: string) => ({})\n};' > src/lib/api/scripts.ts # Mock ratings API with complete interface RUN printf 'export const ratingsApi = {\n submitRating: async (data: any) => ({ scriptId: data.scriptId }),\n rateScript: async (data: any) => ({ scriptId: data.scriptId }),\n getUserRating: async (scriptId: string, userId?: string) => null,\n getScriptRatings: async (scriptId: string) => [],\n getScriptRatingStats: async (scriptId: string) => ({ averageRating: 0, totalRatings: 0, distribution: {} }),\n deleteRating: async (scriptId: string, userId: string) => ({})\n};' > src/lib/api/ratings.ts # Mock analytics API with complete interface RUN printf 'export interface AnalyticsFilters {\n startDate?: Date;\n endDate?: Date;\n}\nexport const analyticsApi = {\n trackEvent: async (data: any) => ({}),\n getAnalytics: async () => ({ views: [], downloads: [], topScripts: [], userGrowth: [] }),\n getAnalyticsEvents: async (filters?: AnalyticsFilters) => [],\n getScriptAnalytics: async (scriptId: string) => ({ views: [], downloads: [] }),\n getPlatformAnalytics: async () => ({ totalUsers: 0, totalScripts: 0 }),\n getUserAnalytics: async (userId: string) => ({ views: [], downloads: [] })\n};' > src/lib/api/analytics.ts # Mock collections API with complete interface RUN printf 'export interface UpdateCollectionData {\n name?: string;\n description?: string;\n}\nexport const collectionsApi = {\n getCollections: async () => [],\n getCollectionById: async (id: string) => null,\n getUserCollections: async (userId: string) => [],\n getPublicCollections: async () => [],\n createCollection: async (data: any) => ({ id: "mock" }),\n updateCollection: async (id: string, data: UpdateCollectionData) => ({ id }),\n deleteCollection: async (id: string) => ({}),\n addScriptToCollection: async (collectionId: string, scriptId: string) => ({}),\n removeScriptFromCollection: async (collectionId: string, scriptId: string) => ({}),\n isScriptInCollection: async (collectionId: string, scriptId: string) => false\n};' > src/lib/api/collections.ts # Mock users API with complete interface RUN printf 'export interface UpdateUserData {\n username?: string;\n displayName?: string;\n bio?: string;\n}\nexport const usersApi = {\n getUser: async (id: string) => null,\n getUserById: async (id: string) => null,\n getAllUsers: async () => [],\n searchUsers: async (query: string) => [],\n createUser: async (data: any) => ({ id: "mock" }),\n updateUser: async (id: string, data: UpdateUserData) => ({ id }),\n updateUserPermissions: async (id: string, permissions: any) => ({ id })\n};' > src/lib/api/users.ts # Create a custom package.json script that skips TypeScript RUN echo '{"name":"scriptshare","scripts":{"build-no-ts":"vite build --mode development"}}' > package-build.json # Skip TypeScript checking and build with Vite only (frontend demo) RUN npx vite build --mode development --config vite.config.ts || echo "Direct vite failed, trying alternative..." && npm run build-no-ts # Verify build output exists RUN ls -la /app/dist # Production stage FROM nginx:alpine # Install curl for health checks RUN apk add --no-cache curl # Copy built files from builder stage COPY --from=builder /app/dist /usr/share/nginx/html # Copy nginx configuration COPY nginx.conf /etc/nginx/nginx.conf # Create nginx pid directory RUN mkdir -p /var/run/nginx # Set proper permissions for nginx directories RUN chmod -R 755 /usr/share/nginx/html RUN mkdir -p /var/cache/nginx /var/log/nginx /var/run/nginx RUN chmod -R 755 /var/cache/nginx /var/log/nginx /var/run/nginx # Run as root for demo purposes (avoid permission issues) # USER nginx # Expose port 80 EXPOSE 80 # Add healthcheck HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -f http://localhost/health || exit 1 # Start nginx CMD ["nginx", "-g", "daemon off;"]