Cybersecurity-Projects/PROJECTS/bug-bounty-platform/docs/research/VITE.md

12 KiB

Production-ready React + Vite 6 template for 2025

A senior frontend engineer building a reusable FastAPI + React + TypeScript template in 2025 should use Vite 6 with pnpm, Biome for linting/formatting, Zustand for client state, TanStack Query for server state, and Tailwind CSS v4 for styling. This configuration prioritizes developer experience, build performance, and production reliability while avoiding over-engineering.

The most significant shift in 2025 is the consolidation of tooling: Biome replaces ESLint + Prettier with 35x faster performance, ESLint's flat config (eslint.config.js) is now mandatory, and Vite 6's Environment API enables better SSR handling. TypeScript's moduleResolution: "bundler" is the correct setting for Vite projects, and the splitVendorChunkPlugin has been deprecated in favor of manual chunks.

Vite 6 brings breaking changes that matter

Vite 6 introduced several breaking changes from Vite 5 that affect production templates. The resolve.conditions default now explicitly includes ['module', 'browser', 'development|production'], affecting how packages resolve. JSON stringify behavior changed to 'auto' mode, and Sass now uses the modern API by default—the legacy API was removed entirely in Vite 7.

A production-ready vite.config.ts should handle environment-specific builds, FastAPI proxy setup, and proper chunk splitting:

import { defineConfig, loadEnv, type PluginOption } from 'vite'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '')
  const isProduction = mode === 'production'
  
  return {
    base: env.VITE_BASE_URL || '/',
    plugins: [
      react(),
      tsconfigPaths(),
      isProduction && visualizer({
        open: true,
        gzipSize: true,
        brotliSize: true,
      }) as PluginOption,
    ].filter(Boolean),
    
    build: {
      target: 'ES2022',
      sourcemap: isProduction ? 'hidden' : true,
      minify: 'esbuild',
      rollupOptions: {
        output: {
          manualChunks: {
            'react-vendor': ['react', 'react-dom'],
            'router': ['react-router-dom'],
          },
        },
      },
    },
    
    server: {
      port: 3000,
      proxy: {
        '/api': {
          target: 'http://localhost:8000',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
        },
      },
    },
  }
})

The splitVendorChunkPlugin was deprecated and removed in Vite 7—use manualChunks for vendor splitting. Source maps should be 'hidden' in production to enable error tracking while preventing source code exposure.

TypeScript configuration requires the bundler resolution strategy

Vite projects require moduleResolution: "bundler" rather than node16, enabling extensionless imports and proper handling of package.json exports. The multi-file tsconfig approach separates browser (app) and Node.js (config) environments:

// tsconfig.app.json
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "noEmit": true,
    "verbatimModuleSyntax": true,
    "erasableSyntaxOnly": true,
    "baseUrl": ".",
    "paths": { "@/*": ["./src/*"] }
  },
  "include": ["src"]
}

Key TypeScript 5.x features worth enabling include verbatimModuleSyntax (enforces explicit type imports), erasableSyntaxOnly (ensures transpiler compatibility), and noUncheckedSideEffectImports (catches missing side-effect imports). The vite-tsconfig-paths plugin automatically syncs path aliases between TypeScript and Vite.

Type-safe environment variables require a declaration file:

// src/vite-env.d.ts
interface ImportMetaEnv {
  readonly VITE_API_URL: string
  readonly VITE_APP_TITLE: string
}

Biome replaces ESLint and Prettier with dramatic speed gains

Biome is production-ready in 2025 with 800,000+ weekly npm downloads, 97% Prettier compatibility, and 35x faster performance than ESLint + Prettier combined. Major companies including Shopify, Airbnb, and Mercedes-Benz use it in production.

// biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.0.0/schema.json",
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "rules": {
      "recommended": true,
      "correctness": { "noUnusedVariables": "error" }
    }
  },
  "organizeImports": { "enabled": true }
}

Migration from ESLint is straightforward: npx @biomejs/biome migrate eslint --write. For teams not ready to switch, ESLint's flat config (eslint.config.js) is now mandatory—the legacy .eslintrc format will be removed in ESLint 10. Use typescript-eslint with eslint-plugin-react, eslint-plugin-react-hooks, and eslint-plugin-jsx-a11y for accessibility.

Oxlint (50-100x faster than ESLint, written in Rust) reached 1.0 stability and can complement ESLint using eslint-plugin-oxlint to disable overlapping rules.

Project structure should be feature-based for scalability

Feature-based organization groups related code by domain, enabling independent team workflows:

src/
├── features/           # Domain modules
│   ├── auth/
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── api/
│   │   └── types.ts
│   └── posts/
├── components/ui/      # Shared primitives (Button, Modal)
├── hooks/              # Shared custom hooks
├── lib/
│   ├── api/client.ts   # Axios instance with interceptors
│   └── query/          # TanStack Query config
├── stores/             # Zustand stores
└── types/              # Global TypeScript types

State management hierarchy for 2025: Use TanStack Query for all server state (API data caching), Zustand (~2.5KB) for global client state, and React Context only for simple shared state like themes. Never store fetched API data in Zustand—let React Query handle caching.

The Zustand pattern with persistence:

import { create } from 'zustand'
import { persist } from 'zustand/middleware'

export const useAuthStore = create()(
  persist(
    (set) => ({
      user: null,
      token: null,
      login: (user, token) => set({ user, token }),
      logout: () => set({ user: null, token: null }),
    }),
    { name: 'auth-storage', partialize: (s) => ({ token: s.token }) }
  )
)

Package managers and enterprise tooling choices

pnpm is the recommended package manager for production: 70% disk space savings, strict dependency resolution preventing phantom dependencies, and excellent monorepo support. Benchmarks show pnpm with cache/lockfile completing installs in 761ms versus npm's 1.3s.

Tool Recommendation
Package manager pnpm (or Bun for new projects)
Git hooks Lefthook (parallel execution, Go binary)
Formatting/linting Biome (or ESLint flat config + Prettier)
Testing Vitest with React Testing Library
API mocking MSW 2.0 for dev and testing
Dep updates Renovate (superior to Dependabot for monorepos)

Essential config files for a production template:

  • .editorconfig — Cross-IDE consistency, still relevant
  • .nvmrc — Node version pinning (critical for CI/CD)
  • browserslist in package.json — Target browser specification
  • lefthook.yml — Pre-commit linting and type checking

Skip Stylelint when using Tailwind CSS—the Tailwind IntelliSense VS Code extension provides sufficient class ordering.

Production hardening requires deliberate security measures

Error tracking with Sentry requires the @sentry/vite-plugin to upload source maps, with filesToDeleteAfterUpload to prevent source code leakage:

sentryVitePlugin({
  sourcemaps: {
    filesToDeleteAfterUpload: ["./**/*.map"],
  },
})

Critical security practices:

  • Never put secrets in VITE_ environment variables—they're embedded in the client bundle
  • Use sourcemap: 'hidden' in production (creates maps for error tracking without exposing them)
  • Implement CSP headers via your server/CDN, not meta tags
  • React auto-escapes JSX, but never use dangerouslySetInnerHTML with user input

Web Vitals tracking is essential. The core metrics for 2025 are LCP (<2.5s), INP (<200ms, replaced FID), and CLS (<0.1). Use the attribution build (web-vitals/attribution) for debugging performance issues.

For bundle optimization, use rollup-plugin-visualizer to identify bloat, implement route-based lazy loading with React.lazy(), and preload routes on hover for faster transitions.

Cutting-edge tools: what's actually production-ready

Tool Status Recommendation
Biome Production-ready Use it—replaces ESLint + Prettier
Bun Stable for package management Viable alternative to pnpm
Oxlint 1.0 stable Complement ESLint for speed
Lightning CSS Stable in Vite Skip if using Tailwind (requires PostCSS)
Rspack 1.0 production-ready Drop-in Webpack replacement
Turbopack ⚠️ Next.js only, alpha for prod Wait for broader ecosystem support

Lightning CSS provides 100x faster CSS processing than PostCSS but isn't compatible with Tailwind CSS. Use it only for vanilla CSS workflows.

CI/CD pipeline essentials

A production CI pipeline should include type checking, linting, bundle size monitoring, and Lighthouse audits:

- run: pnpm install --frozen-lockfile
- run: pnpm typecheck      # tsc --noEmit
- run: pnpm lint           # biome ci
- run: pnpm build
- run: lhci autorun        # Lighthouse CI

Use compressed-size-action or size-limit for bundle size monitoring to catch regressions before deployment. Lighthouse CI with performance budgets (categories:performance > 0.9) prevents performance degradation.

Renovate is superior to Dependabot for monorepos, offering advanced grouping, a dependency dashboard, and support for 90+ package managers versus Dependabot's 14.

Essential plugins for a production Vite template

plugins: [
  react(),
  tsconfigPaths(),                    // Path alias sync
  svgr({ include: '**/*.svg?react' }), // SVG as components
  checker({ typescript: true }),       // Dev-time type errors
  VitePWA({ registerType: 'autoUpdate' }), // If PWA needed
  isProduction && visualizer(),        // Bundle analysis
]

Include PWA support only when offline capability or installability adds genuine user value—it introduces complexity that many applications don't need.

For a senior-level, production-ready React + Vite 6 + FastAPI template in 2025:

  • Build tool: Vite 6 with manualChunks for vendor splitting
  • Package manager: pnpm with strict lockfile
  • TypeScript: Strict mode, moduleResolution: "bundler", path aliases
  • Linting/formatting: Biome (or ESLint flat config + Prettier)
  • Styling: Tailwind CSS v4 with CSS-first configuration
  • State: TanStack Query (server) + Zustand (client)
  • Routing: React Router v6 with lazy loading
  • Testing: Vitest + React Testing Library + MSW
  • Error tracking: Sentry with hidden source maps
  • Git hooks: Lefthook + lint-staged
  • CI/CD: Type check → Lint → Build → Lighthouse

This configuration balances modern tooling with production stability, avoiding bleeding-edge tools that haven't proven enterprise reliability while embracing genuinely superior alternatives like Biome that have earned industry trust.