Performance Optimization and Build Tools

1. Compilation Performance Tuning

Optimization Configuration Impact Trade-off
skipLibCheck "skipLibCheck": true Skip type checking of .d.ts files - 2-5x faster compilation May miss errors in type definitions
incremental "incremental": true Cache compilation info - 40-70% faster rebuilds Requires .tsbuildinfo file storage
skipDefaultLibCheck "skipDefaultLibCheck": true Skip checking default lib.d.ts files Less thorough than skipLibCheck
isolatedModules "isolatedModules": true Ensure each file can be transpiled independently Restricts some TS features (const enums)
Module resolution "moduleResolution": "bundler" Faster resolution for bundlers Only for bundled projects
Exclude patterns "exclude": ["node_modules"] Reduce files to check - significant improvement Must manually include needed files
--diagnostics tsc --diagnostics Show compilation performance metrics Debug information only

Example: Performance-optimized tsconfig.json

// tsconfig.json - Production optimized
{
  "compilerOptions": {
    // Speed optimizations
    "incremental": true,
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    
    // Fast transpilation
    "isolatedModules": true,
    "moduleResolution": "bundler",
    
    // Output settings
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM"],
    
    // Type checking (keep strict for quality)
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    
    // Build caching
    "tsBuildInfoFile": "./dist/.tsbuildinfo",
    
    // Module resolution
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,
    
    // Output
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "exclude": [
    "node_modules",
    "**/*.test.ts",
    "**/*.spec.ts",
    "dist",
    "coverage"
  ]
}

Example: Performance diagnostics

// Run with diagnostics
tsc --diagnostics

// Output example:
Files:              450
Lines:              125000
Nodes:              780000
Identifiers:        245000
Symbols:            198000
Types:              67000
Instantiations:     142000
Memory used:        385MB
I/O read:           0.82s
I/O write:          0.15s
Parse time:         1.45s
Bind time:          0.78s
Check time:         3.21s
Emit time:          0.65s
Total time:         6.09s

// Extended diagnostics for more detail
tsc --diagnostics --extendedDiagnostics

// Analyze slow files
tsc --generateTrace ./trace
// Opens Chrome DevTools Performance tab

Example: Large project optimizations

// For very large codebases (>100k LOC)
{
  "compilerOptions": {
    // Maximum speed settings
    "skipLibCheck": true,
    "incremental": true,
    "isolatedModules": true,
    
    // Reduce type checking scope
    "noEmit": true,  // Let bundler handle transpilation
    
    // Assume changes only affect direct dependencies
    "assumeChangesOnlyAffectDirectDependencies": true,
    
    // Faster but less accurate
    "disableSolutionSearching": true,
    "disableReferencedProjectLoad": true
  },
  // Split into smaller projects
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/ui" },
    { "path": "./packages/utils" }
  ]
}

// Watch mode optimizations
{
  "watchOptions": {
    // Use native file system events (fastest)
    "watchFile": "useFsEvents",
    "watchDirectory": "useFsEvents",
    
    // Fallback options for compatibility
    "fallbackPolling": "dynamicPriority",
    
    // Exclude from watching
    "excludeDirectories": ["**/node_modules", "**/dist"],
    "excludeFiles": ["**/*.test.ts"]
  }
}

2. Incremental Builds and Project References

Feature Configuration Benefit Requirement
Incremental Compilation "incremental": true Cache previous compilation results - faster rebuilds .tsbuildinfo file
Composite Projects "composite": true Enable project references - parallel builds declaration: true required
Project References "references": [{ "path": "..." }] Build dependencies separately - faster monorepo builds Composite projects
Build Mode tsc -b or tsc --build Smart dependency tracking - only rebuild changed projects Project references setup
Parallel Builds tsc -b --verbose Build independent projects concurrently Multi-core CPU
Clean Build tsc -b --clean Remove build outputs and caches Fresh build needed

Example: Monorepo with project references

// Root tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/utils" },
    { "path": "./packages/api" },
    { "path": "./packages/web" }
  ]
}

// packages/core/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "incremental": true,
    "tsBuildInfoFile": "./dist/.tsbuildinfo"
  },
  "include": ["src/**/*"]
}

// packages/api/tsconfig.json (depends on core and utils)
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "references": [
    { "path": "../core" },
    { "path": "../utils" }
  ]
}

// packages/web/tsconfig.json (depends on api, core, utils)
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "jsx": "react-jsx"
  },
  "include": ["src/**/*"],
  "references": [
    { "path": "../api" },
    { "path": "../core" },
    { "path": "../utils" }
  ]
}

Example: Build commands

// package.json scripts
{
  "scripts": {
    // Build all projects with dependencies
    "build": "tsc -b",
    
    // Build specific project
    "build:core": "tsc -b packages/core",
    "build:api": "tsc -b packages/api",
    "build:web": "tsc -b packages/web",
    
    // Watch mode with project references
    "dev": "tsc -b --watch",
    "dev:api": "tsc -b packages/api --watch",
    
    // Clean all build outputs
    "clean": "tsc -b --clean",
    
    // Force rebuild everything
    "rebuild": "tsc -b --force",
    
    // Verbose build output
    "build:verbose": "tsc -b --verbose",
    
    // Dry run (show what would be built)
    "build:dry": "tsc -b --dry"
  }
}

// Build with NPM workspaces (parallel execution)
npm run build --workspaces

// Selective builds based on changes
// Only rebuild changed packages and their dependents
tsc -b packages/core packages/api

// Benefits:
// - Faster builds (only changed projects)
// - Parallel compilation (independent projects)
// - Proper dependency tracking
// - Cached builds (.tsbuildinfo)
// - Better IDE performance

3. Bundle Analysis and Tree Shaking with TypeScript

Technique Configuration Purpose Tool
ES Modules "module": "ESNext" Enable tree shaking - remove unused exports All modern bundlers
Side Effects "sideEffects": false in package.json Mark package as side-effect free - aggressive tree shaking Webpack, Rollup
Named Exports export { func } not export default Better tree shaking - individual function removal Best practice
webpack-bundle-analyzer npm i -D webpack-bundle-analyzer Visualize bundle size - identify large dependencies Webpack
source-map-explorer npm i -D source-map-explorer Analyze bundle composition from source maps Any bundler
Const Enums const enum with isolatedModules: false Inline enum values - zero runtime cost TypeScript compiler

Example: Tree-shakeable library structure

// tsconfig.json - for tree-shakeable output
{
  "compilerOptions": {
    "module": "ESNext",           // ES modules for tree shaking
    "target": "ES2020",
    "declaration": true,
    "declarationMap": true,
    "moduleResolution": "bundler",
    
    // Important for tree shaking
    "isolatedModules": true,      // Each file standalone
    "esModuleInterop": true,
    "preserveConstEnums": false   // Inline const enums
  }
}

// package.json
{
  "name": "my-library",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",     // ES module entry
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",  // ES module
      "require": "./dist/index.cjs", // CommonJS
      "types": "./dist/index.d.ts"
    }
  },
  "sideEffects": false  // Enable aggressive tree shaking
}

// src/index.ts - Use named exports
export { funcA } from './moduleA';
export { funcB } from './moduleB';
export { funcC } from './moduleC';

// Avoid default exports for better tree shaking
// ❌ Bad for tree shaking
export default { funcA, funcB, funcC };

// ✅ Good for tree shaking
export { funcA, funcB, funcC };

// Consumer code - only imports what's needed
import { funcA } from 'my-library';  // Only funcA is bundled

Example: Bundle analysis with Webpack

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

module.exports = {
  // ... webpack config
  
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      reportFilename: 'bundle-report.html',
      openAnalyzer: true,
      generateStatsFile: true,
      statsFilename: 'bundle-stats.json'
    })
  ],
  
  optimization: {
    usedExports: true,  // Mark unused exports
    sideEffects: true,  // Respect package.json sideEffects
    concatenateModules: true,  // Scope hoisting
    minimize: true,
    
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10
        },
        common: {
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true
        }
      }
    }
  }
};

// package.json scripts
{
  "scripts": {
    "analyze": "webpack --mode production --profile --json > stats.json && webpack-bundle-analyzer stats.json",
    "build:analyze": "cross-env ANALYZE=true webpack --mode production"
  }
}

// Using source-map-explorer
npm install -D source-map-explorer

// package.json
{
  "scripts": {
    "analyze:sourcemap": "source-map-explorer 'dist/**/*.js'"
  }
}

4. Webpack TypeScript Configuration and ts-loader

Option Configuration Purpose Performance
ts-loader npm i -D ts-loader Standard TypeScript loader for Webpack Moderate speed, full type checking
transpileOnly transpileOnly: true Skip type checking during build - much faster 5-10x faster, requires separate type check
fork-ts-checker-webpack-plugin npm i -D fork-ts-checker-webpack-plugin Run type checking in separate process Parallel checking, faster builds
thread-loader npm i -D thread-loader Run loaders in worker pool Parallel processing
cache cache: { type: 'filesystem' } Cache webpack compilation - persistent cache Faster rebuilds
babel-loader + @babel/preset-typescript npm i -D babel-loader @babel/preset-typescript Use Babel for transpilation - no type checking Very fast, type check separately

Example: Webpack with ts-loader (production)

// webpack.config.js
const path = require('path');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.ts',
  
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true,  // Skip type checking (done by plugin)
              experimentalWatchApi: true,  // Faster watching
              configFile: 'tsconfig.json'
            }
          }
        ],
        exclude: /node_modules/
      }
    ]
  },
  
  plugins: [
    // Type checking in separate process
    new ForkTsCheckerWebpackPlugin({
      async: false,  // Wait for type checking in production
      typescript: {
        configFile: path.resolve(__dirname, 'tsconfig.json'),
        diagnosticOptions: {
          semantic: true,
          syntactic: true
        }
      }
    })
  ],
  
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  
  // Performance optimizations
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename]
    }
  },
  
  optimization: {
    moduleIds: 'deterministic',
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

Example: Fast development config

// webpack.dev.js
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  mode: 'development',
  devtool: 'eval-source-map',  // Fast source maps
  
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          // Optional: Use thread-loader for parallel processing
          {
            loader: 'thread-loader',
            options: {
              workers: 2,
              workerParallelJobs: 50
            }
          },
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true,
              happyPackMode: true,  // Required with thread-loader
              experimentalWatchApi: true
            }
          }
        ],
        exclude: /node_modules/
      }
    ]
  },
  
  plugins: [
    new ForkTsCheckerWebpackPlugin({
      async: true,  // Don't wait in dev mode (faster)
      typescript: {
        configFile: 'tsconfig.json',
        memoryLimit: 4096  // Increase memory for large projects
      }
    })
  ],
  
  cache: {
    type: 'filesystem',
    allowCollectingMemory: true
  },
  
  devServer: {
    hot: true,
    port: 3000,
    historyApiFallback: true
  }
};

5. Vite TypeScript Integration and HMR

Feature Configuration Benefit Note
Native TS Support Zero config - works out of box No loader needed - uses esbuild for transpilation No type checking by default
vite-plugin-checker npm i -D vite-plugin-checker Type checking during dev and build Recommended for type safety
isolatedModules "isolatedModules": true Required for esbuild - each file independent Restricts some TS features
HMR (Hot Module Replacement) Built-in - automatic Instant updates without full reload Preserves component state
Fast Refresh @vitejs/plugin-react React HMR with state preservation Only for React
Build Speed Uses esbuild for dev, Rollup for prod 10-100x faster than Webpack Excellent DX

Example: Vite configuration with TypeScript

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

export default defineConfig({
  plugins: [
    react({
      // Fast Refresh for React
      fastRefresh: true,
      // Babel options if needed
      babel: {
        parserOpts: {
          plugins: ['decorators-legacy']
        }
      }
    }),
    
    // Type checking plugin
    checker({
      typescript: true,
      eslint: {
        lintCommand: 'eslint "./src/**/*.{ts,tsx}"'
      },
      overlay: {
        initialIsOpen: false,  // Don't auto-open error overlay
        position: 'br'  // Bottom right
      }
    })
  ],
  
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@utils': path.resolve(__dirname, './src/utils')
    }
  },
  
  build: {
    target: 'es2020',
    outDir: 'dist',
    sourcemap: true,
    
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          utils: ['lodash', 'date-fns']
        }
      }
    },
    
    // Optimize chunk size
    chunkSizeWarningLimit: 1000,
    
    // Minification with esbuild (faster)
    minify: 'esbuild'
  },
  
  server: {
    port: 3000,
    open: true,
    hmr: {
      overlay: true
    }
  },
  
  // Optimize dependencies
  optimizeDeps: {
    include: ['react', 'react-dom'],
    exclude: ['@vite/client', '@vite/env']
  }
});

Example: TypeScript config for Vite

// tsconfig.json for Vite
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    
    // Bundler mode (Vite-specific)
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,  // Required for esbuild
    "noEmit": true,  // Vite handles transpilation
    
    // Type checking
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    
    // Path mapping
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"]
    },
    
    // React
    "jsx": "react-jsx"
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

// tsconfig.node.json - for Vite config files
{
  "compilerOptions": {
    "composite": true,
    "skipLibCheck": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true
  },
  "include": ["vite.config.ts"]
}

// package.json scripts
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",  // Type check before build
    "preview": "vite preview",
    "type-check": "tsc --noEmit",
    "type-check:watch": "tsc --noEmit --watch"
  }
}

6. esbuild and SWC TypeScript Compilation

Tool Speed Features Limitations
esbuild 10-100x faster than tsc - written in Go Bundling, minification, transpilation, tree shaking No type checking, limited TS features
SWC 20-70x faster than Babel - written in Rust Transpilation, minification, bundling (experimental) No type checking, newer tool
@swc/core npm i -D @swc/core Core SWC library - standalone or with bundlers Node.js API, CLI
esbuild-loader npm i -D esbuild-loader Use esbuild with Webpack - replace ts-loader Much faster Webpack builds
Turbopack Next.js 13+ bundler - Rust-based Incremental bundling, HMR, fast builds Next.js only currently
Type Checking Separate with tsc --noEmit Run type checking in parallel or CI Two-step process

Example: esbuild configuration

// esbuild.config.js
const esbuild = require('esbuild');

// Build configuration
esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  
  // TypeScript settings
  platform: 'node',
  target: 'es2020',
  format: 'esm',
  
  // Optimizations
  minify: true,
  sourcemap: true,
  treeShaking: true,
  splitting: true,
  
  // External dependencies (not bundled)
  external: ['react', 'react-dom'],
  
  // Loaders for different file types
  loader: {
    '.ts': 'ts',
    '.tsx': 'tsx',
    '.png': 'file',
    '.svg': 'dataurl'
  },
  
  // Define environment variables
  define: {
    'process.env.NODE_ENV': '"production"'
  },
  
  // Watch mode
  watch: false,
  
  // Logging
  logLevel: 'info'
}).catch(() => process.exit(1));

// package.json scripts
{
  "scripts": {
    "build": "npm run type-check && node esbuild.config.js",
    "type-check": "tsc --noEmit",
    "dev": "node esbuild.config.js --watch",
    "dev:check": "concurrently \"npm run type-check:watch\" \"npm run dev\""
  }
}

// Using esbuild programmatically
import * as esbuild from 'esbuild';

// Development with watch
const ctx = await esbuild.context({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outdir: 'dist',
  sourcemap: true,
  platform: 'node',
  target: 'node18'
});

await ctx.watch();
console.log('Watching...');

// Serve mode (dev server)
const { host, port } = await ctx.serve({
  servedir: 'public',
  port: 3000
});
console.log(`Server running at http://${host}:${port}`);

Example: SWC configuration

// .swcrc
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": true,
      "decorators": true,
      "dynamicImport": true
    },
    "transform": {
      "react": {
        "runtime": "automatic",
        "development": false,
        "refresh": true  // Fast Refresh
      },
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "target": "es2020",
    "loose": false,
    "externalHelpers": false,
    "keepClassNames": true
  },
  "module": {
    "type": "es6",
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  },
  "minify": false,
  "sourceMaps": true
}

// Using SWC with Node.js
// Install: npm i -D @swc/core @swc/cli
{
  "scripts": {
    "build": "swc src -d dist",
    "build:watch": "swc src -d dist --watch",
    "type-check": "tsc --noEmit"
  }
}

// Using SWC with Webpack
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        use: {
          loader: 'swc-loader',
          options: {
            jsc: {
              parser: {
                syntax: 'typescript',
                tsx: true
              }
            }
          }
        },
        exclude: /node_modules/
      }
    ]
  }
};

// Using esbuild-loader with Webpack
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'esbuild-loader',
        options: {
          loader: 'tsx',
          target: 'es2020',
          tsconfigRaw: require('./tsconfig.json')
        }
      }
    ]
  },
  plugins: [
    // Use esbuild for minification too (faster)
    new ESBuildMinifyPlugin({
      target: 'es2020',
      css: true
    })
  ]
};

Example: Performance comparison

// Build time comparison for medium project (50k LOC)

// TypeScript Compiler (tsc)
// Time: ~45s
tsc --project tsconfig.json

// Babel + @babel/preset-typescript
// Time: ~35s (no type checking)
babel src --out-dir dist --extensions ".ts,.tsx"

// ts-loader (Webpack)
// Time: ~40s
webpack --mode production

// ts-loader + transpileOnly + fork-ts-checker
// Time: ~25s (parallel type checking)
webpack --mode production

// esbuild-loader (Webpack)
// Time: ~5s (no type checking)
webpack --mode production

// esbuild (standalone)
// Time: ~2s (no type checking)
node esbuild.config.js

// SWC
// Time: ~3s (no type checking)
swc src -d dist

// Vite (esbuild)
// Dev server start: <1s
// Production build: ~5s
vite build

// Recommendation:
// Development: Vite or esbuild with separate tsc --noEmit --watch
// Production: esbuild/SWC + tsc --noEmit in CI pipeline
// Type safety: Always run tsc --noEmit for type checking
Note: Performance optimization best practices:
  • Compilation - Enable skipLibCheck, incremental, use project references for monorepos
  • Build tools - Use esbuild/SWC for fast transpilation, run type checking separately
  • Webpack - Use ts-loader with transpileOnly + fork-ts-checker, enable filesystem cache
  • Vite - Best DX with instant HMR, use vite-plugin-checker for type checking
  • Tree shaking - Use ES modules, named exports, mark packages as side-effect free
  • Analysis - Use webpack-bundle-analyzer or source-map-explorer to identify bloat

Performance and Build Tools Summary

  • Compilation speed - skipLibCheck, incremental builds, project references for 40-70% faster rebuilds
  • Webpack - ts-loader with transpileOnly + fork-ts-checker for parallel type checking
  • Vite - Best development experience with instant HMR, esbuild transpilation, Rollup production builds
  • esbuild - 10-100x faster than tsc, excellent for development and production (no type checking)
  • SWC - Rust-based compiler, 20-70x faster than Babel, growing ecosystem
  • Strategy - Use fast transpiler (esbuild/SWC) + separate type checking with tsc --noEmit