Development Workflow Implementation Tools

1. Vite Hot Module Replacement

Lightning-fast HMR with instant updates without full page reload, preserving application state during development.

Feature Description Benefit Use Case
Fast Refresh Updates React components without losing state Instant feedback Component development
CSS HMR Update styles without reload Live style changes UI/UX development
import.meta.hot API Fine-grained HMR control Custom module updates Advanced scenarios
Dependency Pre-bundling ESBuild pre-bundles node_modules Fast cold start Large dependencies

Example: Vite configuration with HMR

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      // Enable Fast Refresh
      fastRefresh: true,
      // Babel options for custom transforms
      babel: {
        plugins: ['babel-plugin-styled-components']
      }
    })
  ],
  server: {
    port: 3000,
    open: true,
    hmr: {
      // HMR configuration
      overlay: true, // Show errors in browser overlay
      port: 3000
    },
    // Watch options
    watch: {
      usePolling: false, // Use native file watchers
      ignored: ['**/node_modules/**', '**/.git/**']
    }
  },
  // Optimize dependencies
  optimizeDeps: {
    include: ['react', 'react-dom'],
    exclude: ['@your-lib/package']
  }
});

// Custom HMR handling in module
// utils/config.ts
export const config = {
  apiUrl: 'http://localhost:8000',
  timeout: 5000
};

// Accept HMR updates for this module
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    console.log('Config updated:', newModule);
  });
}

Example: React Fast Refresh with state preservation

// Counter.tsx - State is preserved during HMR
import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(c => c + 1)}>
        Increment
      </button>
      {/* Change this text - count state is preserved! */}
      <p>Click the button to count</p>
    </div>
  );
}

// HMR Boundary - Force reload on certain changes
// AppProvider.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

export function AppProvider({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  );
}

// Force full reload if this module changes
if (import.meta.hot) {
  import.meta.hot.dispose(() => {
    // Cleanup before reload
    queryClient.clear();
  });
}

Example: Vite environment variables with HMR

// .env.development
VITE_API_URL=http://localhost:8000
VITE_APP_NAME=My App Dev

// Access in code (HMR updates automatically)
export const config = {
  apiUrl: import.meta.env.VITE_API_URL,
  appName: import.meta.env.VITE_APP_NAME,
  isDev: import.meta.env.DEV,
  isProd: import.meta.env.PROD
};

// TypeScript types for env variables
/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_API_URL: string;
  readonly VITE_APP_NAME: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

// Conditional logic with HMR
if (import.meta.env.DEV) {
  console.log('Development mode - HMR enabled');
}
Performance: Vite HMR is 10-100x faster than Webpack due to native ES modules and esbuild. Cold start in ~500ms, updates in <50ms. Use vite-plugin-inspect to debug HMR issues.

2. Webpack Dev Server Proxy

Configure development proxy to bypass CORS issues and route API requests to backend server during local development.

Proxy Type Configuration Use Case Benefits
Simple Proxy String target URL Single backend API Quick setup, bypass CORS
Path Rewrite Modify request paths Different API versioning Flexible routing
Multiple Proxies Object with multiple targets Microservices Route to different services
WebSocket Proxy ws: true option Real-time connections WebSocket support

Example: Webpack Dev Server proxy configuration

// webpack.config.js
module.exports = {
  devServer: {
    port: 3000,
    // Simple proxy - forward /api to backend
    proxy: {
      '/api': 'http://localhost:8000'
    }
  }
};

// Request: http://localhost:3000/api/users
// Proxied to: http://localhost:8000/api/users

// Advanced proxy with options
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:8000',
        pathRewrite: { '^/api': '' }, // Remove /api prefix
        changeOrigin: true, // Change origin header
        secure: false, // Accept self-signed certificates
        logLevel: 'debug' // Log proxy requests
      },
      // Multiple backend services
      '/auth': {
        target: 'http://localhost:8001',
        changeOrigin: true
      },
      '/graphql': {
        target: 'http://localhost:8002',
        changeOrigin: true
      },
      // WebSocket proxy
      '/ws': {
        target: 'ws://localhost:8003',
        ws: true, // Enable WebSocket proxying
        changeOrigin: true
      }
    }
  }
};

// Request: http://localhost:3000/api/users
// Proxied to: http://localhost:8000/users (api removed)

Example: Vite proxy configuration

// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    proxy: {
      // Simple proxy
      '/api': {
        target: 'http://localhost:8000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      },
      // Proxy with custom headers
      '/auth': {
        target: 'http://localhost:8001',
        changeOrigin: true,
        configure: (proxy, options) => {
          proxy.on('proxyReq', (proxyReq, req, res) => {
            // Add custom headers
            proxyReq.setHeader('X-Custom-Header', 'value');
            console.log('Proxying:', req.method, req.url);
          });
          proxy.on('proxyRes', (proxyRes, req, res) => {
            console.log('Response:', proxyRes.statusCode, req.url);
          });
        }
      },
      // Conditional proxy based on request
      '^/api/v[0-9]+': {
        target: 'http://localhost:8000',
        changeOrigin: true,
        rewrite: (path) => {
          // /api/v1/users -> /v1/users
          return path.replace(/^\/api/, '');
        }
      }
    }
  }
});

// Next.js proxy (next.config.js)
module.exports = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'http://localhost:8000/:path*'
      }
    ];
  }
};

Example: Create React App proxy setup

// package.json - Simple proxy
{
  "proxy": "http://localhost:8000"
}

// All requests to unknown routes are proxied to backend

// src/setupProxy.js - Advanced proxy
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  // API proxy
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:8000',
      changeOrigin: true,
      pathRewrite: {
        '^/api': '' // Remove /api prefix
      },
      onProxyReq: (proxyReq, req, res) => {
        console.log('Proxying:', req.method, req.url);
      }
    })
  );
  
  // Auth service proxy
  app.use(
    '/auth',
    createProxyMiddleware({
      target: 'http://localhost:8001',
      changeOrigin: true
    })
  );
  
  // WebSocket proxy
  app.use(
    '/ws',
    createProxyMiddleware({
      target: 'http://localhost:8003',
      ws: true,
      changeOrigin: true
    })
  );
};
Security Note: Proxy configuration only works in development. In production, configure proper CORS headers on backend or use same-origin deployment. Never expose sensitive backend URLs in client code.

3. GitHub Actions CI CD Pipeline

Automate testing, building, and deployment with GitHub Actions for continuous integration and delivery.

Workflow Stage Actions Purpose Triggers
CI (Continuous Integration) Lint, test, type-check, build Validate code quality Push, PR
CD (Continuous Deployment) Build, deploy to staging/prod Automated deployment Merge to main
Scheduled Jobs Security audits, dependency updates Maintenance tasks Cron schedule
Release Version bump, changelog, publish Package release Tag creation

Example: Complete CI/CD workflow for React app

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [18.x, 20.x]
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint
      
      - name: Type check
        run: npm run type-check
      
      - name: Run tests
        run: npm run test:ci
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage/coverage-final.json
          fail_ci_if_error: true
  
  build:
    runs-on: ubuntu-latest
    needs: lint-and-test
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20.x'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build
        run: npm run build
        env:
          NODE_ENV: production
      
      - name: Upload build artifacts
        uses: actions/upload-artifact@v3
        with:
          name: build-output
          path: dist/
          retention-days: 7

Example: Deployment workflow to Vercel/Netlify

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20.x'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build
        run: npm run build
        env:
          VITE_API_URL: ${{ secrets.PROD_API_URL }}
          VITE_APP_NAME: 'Production App'
      
      # Deploy to Vercel
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
      
      # Or deploy to Netlify
      - name: Deploy to Netlify
        uses: nwtgck/actions-netlify@v2
        with:
          publish-dir: './dist'
          production-deploy: true
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
      
      - name: Notify Slack
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          text: 'Deployment to production completed'
          webhook_url: ${{ secrets.SLACK_WEBHOOK }}
        if: always()

Example: Monorepo CI with Turborepo

# .github/workflows/ci.yml
name: CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2 # For turbo to detect changes
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20.x'
      
      - name: Install pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8
      
      - name: Get pnpm store directory
        id: pnpm-cache
        run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
      
      - name: Setup pnpm cache
        uses: actions/cache@v3
        with:
          path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Build
        run: pnpm turbo run build
      
      - name: Test
        run: pnpm turbo run test
      
      - name: Lint
        run: pnpm turbo run lint

Example: Automated dependency updates with Dependabot

# .github/dependabot.yml
version: 2
updates:
  # Enable npm dependency updates
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
      day: "monday"
    open-pull-requests-limit: 10
    reviewers:
      - "team-frontend"
    labels:
      - "dependencies"
      - "automated"
    # Group minor/patch updates
    groups:
      production-dependencies:
        patterns:
          - "*"
        update-types:
          - "minor"
          - "patch"
  
  # GitHub Actions updates
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

# Auto-merge Dependabot PRs (workflow)
# .github/workflows/dependabot-auto-merge.yml
name: Dependabot auto-merge
on: pull_request

permissions:
  pull-requests: write
  contents: write

jobs:
  dependabot:
    runs-on: ubuntu-latest
    if: github.actor == 'dependabot[bot]'
    steps:
      - name: Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v1
      
      - name: Enable auto-merge for Dependabot PRs
        if: steps.metadata.outputs.update-type == 'version-update:semver-patch'
        run: gh pr merge --auto --squash "$PR_URL"
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
Best Practice: Cache node_modules and build outputs for faster CI. Run jobs in parallel when possible. Use matrix strategy for multi-version testing. Set up branch protection rules requiring CI pass.

4. Pre-commit Hooks lint-staged

Run linters and formatters only on staged files before commit to catch issues early and maintain code quality.

Tool Purpose When Runs Performance
Husky Git hooks management Various git events Instant hook registration
lint-staged Run commands on staged files only Pre-commit Fast (only changed files)
commitlint Validate commit messages Commit-msg hook Instant validation
pre-push Run tests before push Pre-push Can be slow (full tests)

Example: Complete pre-commit hooks setup

// Installation
npm install -D husky lint-staged @commitlint/cli @commitlint/config-conventional

// Initialize Husky
npx husky init

// package.json
{
  "scripts": {
    "prepare": "husky",
    "lint": "eslint .",
    "format": "prettier --write .",
    "type-check": "tsc --noEmit",
    "test": "vitest"
  },
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,css,scss}": [
      "prettier --write"
    ],
    "*.{ts,tsx}": [
      () => "tsc --noEmit" // Type check all files, not just staged
    ]
  }
}

// .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

// .husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit $1

// .husky/pre-push
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run type-check
npm run test -- --run

// commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',     // New feature
        'fix',      // Bug fix
        'docs',     // Documentation
        'style',    // Formatting
        'refactor', // Code restructuring
        'test',     // Tests
        'chore',    // Maintenance
        'perf',     // Performance
        'ci',       // CI/CD
        'build',    // Build system
        'revert'    // Revert commit
      ]
    ],
    'subject-case': [2, 'always', 'sentence-case']
  }
};

// Valid commit messages:
// feat: add user authentication
// fix: resolve navigation bug
// docs: update README installation steps
// added new feature (missing type)
// Fix: bug (wrong case)

Example: Advanced lint-staged configuration

// .lintstagedrc.js - More control
module.exports = {
  // TypeScript/JavaScript files
  '*.{ts,tsx}': [
    'eslint --fix --max-warnings=0',
    'prettier --write',
    () => 'tsc --noEmit --pretty' // Run for all files
  ],
  
  // JavaScript files
  '*.{js,jsx}': [
    'eslint --fix --max-warnings=0',
    'prettier --write'
  ],
  
  // Styles
  '*.{css,scss}': [
    'stylelint --fix',
    'prettier --write'
  ],
  
  // JSON/Markdown
  '*.{json,md}': ['prettier --write'],
  
  // Test files - run related tests
  '**/*.test.{ts,tsx}': [
    (filenames) => {
      const tests = filenames.map(f => `--testPathPattern=${f}`).join(' ');
      return `vitest run ${tests}`;
    }
  ],
  
  // Package.json - validate and sort
  'package.json': [
    'sort-package-json',
    'prettier --write'
  ]
};

// Skip hooks when needed
// git commit --no-verify -m "emergency fix"
// git push --no-verify

Example: Monorepo lint-staged with Turborepo

// Root .lintstagedrc.js
module.exports = {
  '*': 'prettier --write --ignore-unknown',
  '*.{ts,tsx,js,jsx}': (filenames) => {
    // Only lint files in affected packages
    const packages = new Set(
      filenames.map(f => f.split('/')[1]) // Extract package name
    );
    
    return Array.from(packages).map(
      pkg => `turbo run lint --filter=./${pkg}`
    );
  }
};

// Per-package hooks
// apps/web/.lintstagedrc.js
module.exports = {
  '*.{ts,tsx}': [
    'eslint --fix',
    'prettier --write',
    () => 'tsc --noEmit -p apps/web'
  ]
};

// Root package.json
{
  "scripts": {
    "prepare": "husky"
  },
  "lint-staged": {
    "apps/**/*.{ts,tsx}": [
      "turbo run lint --filter=./apps/*"
    ],
    "packages/**/*.{ts,tsx}": [
      "turbo run lint --filter=./packages/*"
    ]
  }
}
Performance Tip: Avoid running full test suite in pre-commit (too slow). Use pre-push for tests. For type-checking, use () => 'tsc --noEmit' to check all files, not individual staged files.

5. Storybook Component Documentation

Develop, document, and test UI components in isolation with comprehensive documentation and interactive examples.

Feature Purpose Benefit Add-on
Component Isolation Develop without full app Faster iteration Built-in
Interactive Docs Auto-generate documentation Living style guide @storybook/addon-docs
Controls Modify props in UI Test all states @storybook/addon-controls
Actions Log event handlers Debug interactions @storybook/addon-actions
Accessibility A11y testing Catch issues early @storybook/addon-a11y

Example: Storybook setup and configuration

// Installation
npx storybook@latest init

// .storybook/main.ts
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-a11y',
    '@storybook/addon-coverage'
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {}
  },
  docs: {
    autodocs: 'tag' // Auto-generate docs page
  }
};

export default config;

// .storybook/preview.ts
import type { Preview } from '@storybook/react';
import '../src/styles/globals.css';

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i
      }
    },
    backgrounds: {
      default: 'light',
      values: [
        { name: 'light', value: '#ffffff' },
        { name: 'dark', value: '#1a1a1a' }
      ]
    }
  }
};

export default preview;

Example: Component stories with all variants

// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Components/Button',
  component: Button,
  tags: ['autodocs'],
  argTypes: {
    variant: {
      control: 'select',
      options: ['primary', 'secondary', 'danger']
    },
    size: {
      control: 'radio',
      options: ['sm', 'md', 'lg']
    },
    onClick: { action: 'clicked' }
  }
};

export default meta;
type Story = StoryObj<typeof Button>;

// Default story
export const Primary: Story = {
  args: {
    variant: 'primary',
    children: 'Button'
  }
};

// Variants
export const Secondary: Story = {
  args: {
    variant: 'secondary',
    children: 'Button'
  }
};

export const Danger: Story = {
  args: {
    variant: 'danger',
    children: 'Delete'
  }
};

// Sizes
export const Small: Story = {
  args: {
    size: 'sm',
    children: 'Small Button'
  }
};

export const Large: Story = {
  args: {
    size: 'lg',
    children: 'Large Button'
  }
};

// States
export const Disabled: Story = {
  args: {
    disabled: true,
    children: 'Disabled'
  }
};

export const Loading: Story = {
  args: {
    loading: true,
    children: 'Loading...'
  }
};

// With icons
export const WithIcon: Story = {
  args: {
    children: (
      <>
        <span>🚀</span> Launch
      </>
    )
  }
};

Example: Interactive stories with play function

// LoginForm.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { within, userEvent, expect } from '@storybook/test';
import { LoginForm } from './LoginForm';

const meta: Meta<typeof LoginForm> = {
  title: 'Features/LoginForm',
  component: LoginForm,
  parameters: {
    layout: 'centered'
  }
};

export default meta;
type Story = StoryObj<typeof LoginForm>;

// Basic story
export const Default: Story = {};

// Interactive test
export const FilledForm: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    // Find and fill inputs
    const emailInput = canvas.getByLabelText('Email');
    const passwordInput = canvas.getByLabelText('Password');
    const submitButton = canvas.getByRole('button', { name: /sign in/i });
    
    // Simulate user interaction
    await userEvent.type(emailInput, 'user@example.com');
    await userEvent.type(passwordInput, 'password123');
    
    // Verify inputs
    await expect(emailInput).toHaveValue('user@example.com');
    await expect(passwordInput).toHaveValue('password123');
    
    // Submit form
    await userEvent.click(submitButton);
  }
};

// Error state
export const WithErrors: Story = {
  args: {
    errors: {
      email: 'Invalid email format',
      password: 'Password is required'
    }
  }
};

Example: MDX documentation with embedded stories

<!-- Button.stories.mdx -->
import { Canvas, Meta, Story, ArgTypes } from '@storybook/blocks';
import { Button } from './Button';
import * as ButtonStories from './Button.stories';

<Meta of={ButtonStories} />

# Button Component

A versatile button component with multiple variants and sizes.

## Usage

```tsx
import { Button } from '@/components/Button';

function App() {
  return (
    <Button variant="primary" onClick={() => alert('Clicked!')}>
      Click Me
    </Button>
  );
}
```

## Variants

<Canvas of={ButtonStories.Primary} />
<Canvas of={ButtonStories.Secondary} />
<Canvas of={ButtonStories.Danger} />

## Props

<ArgTypes of={Button} />

## Accessibility

- Keyboard navigable with Tab
- Supports aria-label and aria-describedby
- Disabled state properly communicated to screen readers

## Best Practices

- Use semantic button text (avoid "Click here")
- Provide loading state feedback
- Use appropriate variant for action importance
Storybook Benefits: Component catalog, visual testing with Chromatic, interaction testing, accessibility auditing, responsive design testing, and living documentation for design systems.

6. Bundle Analyzer Performance Monitoring

Analyze bundle size, identify large dependencies, and optimize JavaScript bundles for better performance.

Tool Platform Features Best For
webpack-bundle-analyzer Webpack Interactive treemap, module sizes Webpack projects
rollup-plugin-visualizer Vite/Rollup Multiple chart types, treemap Vite projects
source-map-explorer Any bundler Source map analysis Generic analysis
bundlephobia Web service npm package size lookup Dependency evaluation

Example: Webpack Bundle Analyzer setup

// Installation
npm install -D webpack-bundle-analyzer

// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: process.env.ANALYZE ? 'server' : 'disabled',
      openAnalyzer: true,
      generateStatsFile: true,
      statsFilename: 'bundle-stats.json'
    })
  ]
};

// package.json
{
  "scripts": {
    "build": "webpack --mode production",
    "build:analyze": "ANALYZE=true webpack --mode production"
  }
}

// Run analysis
npm run build:analyze

// Create React App
npm install -D webpack-bundle-analyzer
npm run build
npx webpack-bundle-analyzer build/static/js/*.js

Example: Vite bundle analysis with visualizer

// Installation
npm install -D rollup-plugin-visualizer

// vite.config.ts
import { defineConfig } from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig({
  plugins: [
    visualizer({
      filename: './dist/stats.html',
      open: true,
      gzipSize: true,
      brotliSize: true,
      template: 'treemap' // or 'sunburst', 'network'
    })
  ],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vendor-react': ['react', 'react-dom'],
          'vendor-ui': ['@mui/material', '@emotion/react'],
          'vendor-utils': ['lodash-es', 'date-fns']
        }
      }
    }
  }
});

// package.json
{
  "scripts": {
    "build": "vite build",
    "build:analyze": "vite build --mode production"
  }
}

// Output: dist/stats.html with interactive visualization

Example: Next.js bundle analysis

// Installation
npm install -D @next/bundle-analyzer

// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true'
});

module.exports = withBundleAnalyzer({
  // Next.js config
  reactStrictMode: true,
  swcMinify: true,
  
  // Optimize bundle
  webpack: (config, { isServer }) => {
    if (!isServer) {
      // Client-side optimizations
      config.optimization.splitChunks = {
        chunks: 'all',
        cacheGroups: {
          default: false,
          vendors: false,
          // Vendor chunk
          vendor: {
            name: 'vendor',
            chunks: 'all',
            test: /node_modules/
          },
          // Common chunks
          common: {
            name: 'common',
            minChunks: 2,
            chunks: 'all',
            priority: 10,
            reuseExistingChunk: true,
            enforce: true
          }
        }
      };
    }
    return config;
  }
});

// package.json
{
  "scripts": {
    "build": "next build",
    "analyze": "ANALYZE=true next build"
  }
}

// Run: npm run analyze
// Opens two browser tabs: client and server bundles

Example: Bundle size budgets and monitoring

// webpack.config.js - Size budgets
module.exports = {
  performance: {
    maxAssetSize: 250000, // 250kb
    maxEntrypointSize: 400000, // 400kb
    hints: 'error', // or 'warning'
    assetFilter: (assetFilename) => {
      return assetFilename.endsWith('.js');
    }
  }
};

// vite.config.ts - Size warnings
export default defineConfig({
  build: {
    chunkSizeWarningLimit: 500, // 500kb warning threshold
    rollupOptions: {
      output: {
        manualChunks(id) {
          // Split large dependencies
          if (id.includes('node_modules')) {
            if (id.includes('react')) return 'vendor-react';
            if (id.includes('@mui')) return 'vendor-ui';
            if (id.includes('lodash')) return 'vendor-utils';
            return 'vendor';
          }
        }
      }
    }
  }
});

// package.json - Bundle size tracking
{
  "scripts": {
    "size": "size-limit",
    "size:why": "size-limit --why"
  },
  "size-limit": [
    {
      "path": "dist/index.js",
      "limit": "200 KB"
    },
    {
      "path": "dist/vendor.js",
      "limit": "300 KB"
    }
  ]
}

// .github/workflows/size.yml - CI size check
name: Size Check
on: pull_request

jobs:
  size:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: andresz1/size-limit-action@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

Development Workflow Optimization Checklist