Skip to main content

Production Build Process

Cat Web uses Vite to create highly optimized production builds with TypeScript compilation, code splitting, and minification.

Building the Application

1

Run TypeScript Compiler

The build process first type-checks your code:
npm run build
This executes: tsc -b && vite build
2

TypeScript Build Info

TypeScript compiles in build mode (-b flag), which:
  • Checks all type definitions
  • Creates build info for incremental compilation
  • Fails the build if type errors are found
  • Stores build cache in node_modules/.tmp/
3

Vite Build

After successful type checking, Vite builds the production bundle:
  • Minifies JavaScript and CSS
  • Optimizes assets (images, fonts)
  • Creates code-split chunks
  • Generates source maps
  • Outputs to dist/ directory
The build command runs TypeScript compilation first. If type errors exist, the build will fail before Vite runs. This ensures type safety in production.

Build Output

After a successful build, the dist/ directory contains:
dist/
├── assets/
│   ├── index-[hash].js      # Main application bundle
│   ├── index-[hash].css     # Compiled styles
│   └── [component]-[hash].js # Code-split chunks
├── index.html               # Entry HTML file
└── vite.svg                 # Static assets

Build Optimizations

Vite automatically applies:
  • Code Splitting: Separates vendor dependencies and route-based chunks
  • Tree Shaking: Removes unused code from the bundle
  • Minification: Reduces file sizes using esbuild
  • Asset Optimization: Compresses and optimizes images
  • CSS Inlining: Critical CSS inlined in HTML
  • Hash-based Caching: File names include content hashes for cache busting

Preview Production Build

Before deploying, test the production build locally:
npm run preview
This command:
  1. Serves the dist/ folder on a local server (usually http://localhost:4173)
  2. Simulates production environment behavior
  3. Allows testing with production optimizations enabled
The preview server is for local testing only. Never use vite preview in production. Use a proper web server like Nginx, Apache, or a CDN.

TypeScript Compilation

Compiler Configuration

Cat Web uses multiple TypeScript configurations:
  • tsconfig.json - Root config referencing other configs
  • tsconfig.app.json - Application source code settings
  • tsconfig.node.json - Node.js tools and build scripts

Key Compiler Options

tsconfig.app.json
{
  "compilerOptions": {
    "target": "ES2020",           // Modern JavaScript output
    "module": "ESNext",            // ESM modules
    "strict": true,                // Strict type checking
    "noEmit": true,                // Vite handles output
    "jsx": "react-jsx",            // React 19 JSX transform
    "moduleResolution": "bundler", // Optimized for Vite
    "isolatedModules": true        // Required for Vite
  }
}

Build-Time Type Checking

The tsc -b command:
  • Performs incremental compilation using build info
  • Checks all included TypeScript files
  • Validates type definitions and imports
  • Fails fast on type errors
  • Faster than tsc --noEmit for large projects

Environment Variables in Production

Setting Production Variables

Environment variables must be set during the build process:
# Option 1: Inline with build command
VITE_API_BASE_URL=https://api.production.com npm run build

# Option 2: Use .env.production file
echo "VITE_API_BASE_URL=https://api.production.com" > .env.production
npm run build

Required Variables

Ensure these are set before building:
.env.production
VITE_AUTH0_DOMAIN=your-prod-domain.auth0.com
VITE_AUTH0_CLIENT_ID=your-prod-client-id
VITE_AUTH0_AUDIENCE=your-prod-audience
VITE_API_BASE_URL=https://api.your-domain.com
Environment variables are embedded into the build at compile time. To change them, you must rebuild the application.

Variable Security

Only VITE_ prefixed variables are exposed to the client:
# ✅ Exposed to client
VITE_API_BASE_URL=https://api.example.com

# ❌ Not exposed (no VITE_ prefix)
API_SECRET_KEY=secret123
Never put sensitive secrets in VITE_ variables. They are visible in the compiled JavaScript bundle.

Deployment Considerations

Static File Hosting

Cat Web builds to static files that can be hosted on:
  • CDNs: Cloudflare Pages, Vercel, Netlify
  • Cloud Storage: AWS S3 + CloudFront, Google Cloud Storage
  • Web Servers: Nginx, Apache, Caddy
  • Container Platforms: Docker with nginx base image

Server Configuration

For single-page applications (SPAs), configure your server to: Nginx Example:
server {
  listen 80;
  server_name your-domain.com;
  root /var/www/cat-web/dist;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }

  # Cache static assets
  location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
  }
}
Apache Example (.htaccess):
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

Docker Deployment

Dockerfile Example:
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Build Optimization Tips

Analyze Bundle Size

Use Vite’s build analysis:
npm run build -- --mode production
Vite outputs chunk sizes in the terminal. Look for:
  • Large vendor chunks (consider code splitting)
  • Duplicate dependencies (check package.json)
  • Oversized assets (compress images before importing)

Reduce Bundle Size

1

Lazy Load Routes

Use React.lazy() for route-based code splitting:
import { lazy } from 'react'

const Dashboard = lazy(() => import('@Spa/pages/Dashboard/Dashboard'))
2

Optimize Images

Compress images before adding to src/assets/. Consider using WebP format for better compression.
3

Tree-Shakeable Imports

Import only what you need from large libraries:
// ❌ Imports entire library
import * as MUI from '@mui/material'

// ✅ Tree-shakeable import
import { Button, TextField } from '@mui/material'
4

Review Dependencies

Regularly audit dependencies:
npm outdated
npm audit

Common Build Issues

TypeScript Errors

Problem: Build fails with type errors Solution:
# Check types without building
npx tsc --noEmit

# Fix errors shown in output
# Then rebuild
npm run build

Out of Memory

Problem: Build fails with “JavaScript heap out of memory” Solution:
# Increase Node.js memory limit
NODE_OPTIONS="--max-old-space-size=4096" npm run build

Missing Environment Variables

Problem: Environment variables undefined in production Solution: Ensure variables are set before build, not at runtime. Rebuild after changing .env.production.

Build Scripts Reference

npm run build

Continuous Integration

Example GitHub Actions workflow:
.github/workflows/build.yml
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint
      
      - name: Build
        env:
          VITE_AUTH0_DOMAIN: ${{ secrets.AUTH0_DOMAIN }}
          VITE_AUTH0_CLIENT_ID: ${{ secrets.AUTH0_CLIENT_ID }}
          VITE_AUTH0_AUDIENCE: ${{ secrets.AUTH0_AUDIENCE }}
          VITE_API_BASE_URL: ${{ secrets.API_BASE_URL }}
        run: npm run build
      
      - name: Upload dist
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

Next Steps

Development

Return to development workflow

Configuration

Review configuration settings

Build docs developers (and LLMs) love