Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.

Minify all JavaScript files

All JavaScript files are minified to reduce file size and improve loading performance.

Utilities
Quick take
Typical fix time 15 min
  • Enable minification in your build tool (Vite, webpack, etc.)
  • Use Terser for modern JavaScript minification
  • Enable tree-shaking to remove unused code
  • Typical reduction: 50-70% file size savings
Why it matters: Unminified JavaScript adds hundreds of KB to page weight, slowing down load times especially on mobile networks where every byte counts.

Rule Details

JavaScript minification removes unnecessary characters, shortens variable names, and optimizes code structure to reduce file sizes and improve loading performance.

Code Examples

Unminified JavaScript (Development)

/**
 * User authentication module
 * Handles login, logout, and session management
 */
class UserAuthenticator {
  constructor(apiBaseUrl, options = {}) {
    this.apiBaseUrl = apiBaseUrl;
    this.options = {
      timeout: 5000,
      retries: 3,
      ...options
    };
    this.currentUser = null;
    this.authToken = localStorage.getItem('authToken');
  }
 
  /**
   * Authenticate user with email and password
   * @param {string} email - User email address
   * @param {string} password - User password
   * @returns {Promise<Object>} Authentication result
   */
  async login(email, password) {
    try {
      const response = await fetch(`${this.apiBaseUrl}/auth/login`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          email: email,
          password: password
        })
      });
 
      if (!response.ok) {
        throw new Error(`Authentication failed: ${response.status}`);
      }
 
      const data = await response.json();
      this.authToken = data.token;
      this.currentUser = data.user;
 
      localStorage.setItem('authToken', this.authToken);
      localStorage.setItem('user', JSON.stringify(this.currentUser));
 
      return {
        success: true,
        user: this.currentUser,
        message: 'Authentication successful'
      };
 
    } catch (error) {
      console.error('Login error:', error);
      return {
        success: false,
        error: error.message
      };
    }
  }
 
  /**
   * Logout current user
   */
  logout() {
    this.authToken = null;
    this.currentUser = null;
    localStorage.removeItem('authToken');
    localStorage.removeItem('user');
    window.location.href = '/login';
  }
}
 
// Initialize authenticator
const auth = new UserAuthenticator('https://api.example.com', {
  timeout: 10000,
  retries: 5
});
 
export { UserAuthenticator, auth };

Minified JavaScript (Production)

class UserAuthenticator{constructor(e,t={}){this.apiBaseUrl=e,this.options={timeout:5e3,retries:3,...t},this.currentUser=null,this.authToken=localStorage.getItem("authToken")}async login(e,t){try{const n=await fetch(`${this.apiBaseUrl}/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:e,password:t})});if(!n.ok)throw new Error(`Authentication failed: ${n.status}`);const s=await n.json();return this.authToken=s.token,this.currentUser=s.user,localStorage.setItem("authToken",this.authToken),localStorage.setItem("user",JSON.stringify(this.currentUser)),{success:!0,user:this.currentUser,message:"Authentication successful"}}catch(n){return console.error("Login error:",n),{success:!1,error:n.message}}}logout(){this.authToken=null,this.currentUser=null,localStorage.removeItem("authToken"),localStorage.removeItem("user"),window.location.href="/login"}}const auth=new UserAuthenticator("https://api.example.com",{timeout:1e4,retries:5});export{UserAuthenticator,auth};

Size Reduction: ~85% smaller (from ~2.1KB to ~0.32KB)

Why It Matters

Unminified JavaScript adds hundreds of KB to page weight, slowing down load times especially on mobile networks where every byte counts.

Build Tool Configuration

Webpack with Terser

// webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');
 
module.exports = {
  mode: 'production',
 
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            // Remove console.* statements
            drop_console: true,
            // Remove debugger statements
            drop_debugger: true,
            // Remove unused functions
            unused: true,
            // Remove dead code
            dead_code: true,
            // Optimize comparisons
            comparisons: true,
            // Optimize conditionals
            conditionals: true,
            // Evaluate constant expressions
            evaluate: true,
            // Optimize boolean contexts
            booleans: true,
            // Optimize loops
            loops: true,
            // Join consecutive var statements
            join_vars: true,
            // Remove unreachable code
            unreachable: true
          },
          mangle: {
            // Mangle top-level names
            toplevel: true,
            // Preserve function names for debugging
            keep_fnames: false,
            // Mangle properties
            properties: {
              // Don't mangle quoted properties
              quoted: false
            }
          },
          format: {
            // Remove comments
            comments: false,
            // ASCII only
            ascii_only: true
          }
        },
        // Enable parallel processing
        parallel: true,
        // Extract comments to separate file
        extractComments: false
      })
    ],
 
    // Split chunks for better caching
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

Vite JavaScript Minification

// vite.config.js
import { defineConfig } from 'vite';
 
export default defineConfig({
  build: {
    minify: 'terser', // or 'esbuild' for faster builds
 
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true,
        pure_funcs: ['console.log', 'console.info'],
        passes: 2 // Multiple passes for better optimization
      },
      mangle: {
        toplevel: true,
        properties: {
          regex: /^_/ // Mangle properties starting with underscore
        }
      },
      format: {
        comments: false
      }
    },
 
    rollupOptions: {
      output: {
        manualChunks: {
          // Separate vendor code
          vendor: ['react', 'react-dom'],
          // Separate utils
          utils: ['lodash', 'date-fns']
        }
      }
    }
  }
});

Rollup with Minification

// rollup.config.js
import { terser } from 'rollup-plugin-terser';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
 
export default {
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.min.js',
    format: 'iife',
    name: 'MyApp'
  },
 
  plugins: [
    nodeResolve(),
    commonjs(),
 
    // Minify in production
    process.env.NODE_ENV === 'production' && terser({
      compress: {
        drop_console: true,
        drop_debugger: true,
        pure_getters: true,
        unsafe_comps: true,
        unsafe_math: true,
        passes: 2
      },
      mangle: {
        toplevel: true
      },
      format: {
        comments: false
      }
    })
  ].filter(Boolean)
};

Framework Examples

Next.js Automatic Minification

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  compiler: {
    // Remove console statements in production
    removeConsole: process.env.NODE_ENV === 'production',
 
    // Enable React compiler optimizations
    reactRemoveProperties: process.env.NODE_ENV === 'production',
 
    // Remove React DevTools in production
    reactStrictMode: true
  },
 
  // Custom webpack configuration
  webpack: (config, { dev, isServer }) => {
    if (!dev && !isServer) {
      // Additional optimizations for client-side production
      config.optimization.minimize = true;
 
      // Custom Terser configuration
      config.optimization.minimizer[0].options.terserOptions = {
        ...config.optimization.minimizer[0].options.terserOptions,
        compress: {
          ...config.optimization.minimizer[0].options.terserOptions.compress,
          drop_console: true,
          pure_funcs: ['console.log', 'console.info', 'console.debug']
        }
      };
    }
 
    return config;
  },
 
  experimental: {
    // Enable SWC minification (faster than Terser)
    swcMinify: true
  }
};
 
module.exports = nextConfig;

Create React App with Custom Minification

// craco.config.js
const { when, whenProd } = require('@craco/craco');
 
module.exports = {
  webpack: {
    configure: (webpackConfig) => {
      // Customize Terser options in production
      whenProd(() => {
        const minimizerIndex = webpackConfig.optimization.minimizer.findIndex(
          minimizer => minimizer.constructor.name === 'TerserPlugin'
        );
 
        if (minimizerIndex > -1) {
          webpackConfig.optimization.minimizer[minimizerIndex].options.terserOptions = {
            ...webpackConfig.optimization.minimizer[minimizerIndex].options.terserOptions,
            compress: {
              drop_console: true,
              drop_debugger: true,
              pure_funcs: ['console.log', 'console.info']
            },
            mangle: {
              toplevel: true
            }
          };
        }
      });
 
      return webpackConfig;
    }
  }
};

Vue CLI Minification

// vue.config.js
module.exports = {
  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      // Custom Terser configuration
      config.optimization.minimizer[0].options.terserOptions = {
        compress: {
          drop_console: true,
          drop_debugger: true,
          pure_funcs: ['console.log']
        },
        mangle: {
          safari10: true,
          toplevel: true
        }
      };
    }
  },
 
  chainWebpack: config => {
    config
      .when(process.env.NODE_ENV === 'production', config => {
        config
          .plugin('terser')
          .tap(args => {
            args[0].terserOptions.compress = {
              ...args[0].terserOptions.compress,
              drop_console: true,
              pure_funcs: ['console.log', 'console.info']
            };
            return args;
          });
      });
  }
};

Manual Minification

Command Line Tools

# Using Terser CLI
npm install -g terser
terser input.js -o output.min.js --compress --mangle
 
# With advanced options
terser input.js -o output.min.js \
  --compress drop_console=true,drop_debugger=true \
  --mangle toplevel=true \
  --comments false
 
# Using UglifyJS
npm install -g uglify-js
uglifyjs input.js -o output.min.js -c -m
 
# Batch processing
find src/js -name "*.js" -exec terser {} -o {}.min \;

Node.js Script

// scripts/minify-js.js
const fs = require('fs');
const path = require('path');
const { minify } = require('terser');
 
async function minifyJavaScript(inputPath, outputPath) {
  try {
    const code = fs.readFileSync(inputPath, 'utf8');
 
    const result = await minify(code, {
      compress: {
        drop_console: true,
        drop_debugger: true,
        unused: true,
        dead_code: true,
        conditionals: true,
        evaluate: true,
        booleans: true,
        loops: true,
        passes: 2
      },
      mangle: {
        toplevel: true,
        properties: {
          regex: /^_/
        }
      },
      format: {
        comments: false,
        beautify: false
      },
      sourceMap: {
        filename: path.basename(outputPath),
        url: `${path.basename(outputPath)}.map`
      }
    });
 
    if (result.error) {
      throw result.error;
    }
 
    // Write minified code
    fs.writeFileSync(outputPath, result.code);
 
    // Write source map
    if (result.map) {
      fs.writeFileSync(`${outputPath}.map`, result.map);
    }
 
    // Calculate savings
    const originalSize = Buffer.byteLength(code, 'utf8');
    const minifiedSize = Buffer.byteLength(result.code, 'utf8');
    const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
 
    console.log(`✅ ${inputPath} → ${outputPath}`);
    console.log(`   ${originalSize} bytes → ${minifiedSize} bytes (${savings}% smaller)`);
 
  } catch (error) {
    console.error(`❌ Error minifying ${inputPath}:`, error.message);
  }
}
 
// Process all JS files
async function minifyAllJS() {
  const srcDir = 'src/js';
  const distDir = 'dist/js';
 
  if (!fs.existsSync(distDir)) {
    fs.mkdirSync(distDir, { recursive: true });
  }
 
  const jsFiles = fs.readdirSync(srcDir)
    .filter(file => file.endsWith('.js') && !file.endsWith('.min.js'));
 
  for (const file of jsFiles) {
    const inputPath = path.join(srcDir, file);
    const outputPath = path.join(distDir, file.replace('.js', '.min.js'));
    await minifyJavaScript(inputPath, outputPath);
  }
}
 
minifyAllJS();

Advanced Optimization Techniques

Tree Shaking with Minification

// webpack.config.js
module.exports = {
  mode: 'production',
 
  optimization: {
    // Enable tree shaking
    usedExports: true,
    sideEffects: false,
 
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            // More aggressive tree shaking
            unused: true,
            dead_code: true,
            pure_getters: true,
            pure_funcs: [
              'Math.floor',
              'Math.ceil',
              'console.log',
              'console.info'
            ]
          }
        }
      })
    ]
  },
 
  // Mark packages as side-effect free
  module: {
    rules: [
      {
        test: /\.js$/,
        sideEffects: false
      }
    ]
  }
};

Code Splitting with Minification

// Dynamic imports for code splitting
const LazyComponent = lazy(() => import('./LazyComponent'));
 
// Webpack will automatically minify each chunk
const AdminPanel = lazy(() =>
  import(
    /* webpackChunkName: "admin-panel" */
    './AdminPanel'
  )
);
 
// Preload critical chunks
const CriticalComponent = lazy(() =>
  import(
    /* webpackChunkName: "critical" */
    /* webpackPreload: true */
    './CriticalComponent'
  )
);

Service Worker Minification

// webpack.config.js with Workbox
const { GenerateSW } = require('workbox-webpack-plugin');
 
module.exports = {
  plugins: [
    new GenerateSW({
      // Minify the generated service worker
      swDest: 'sw.js',
      clientsClaim: true,
      skipWaiting: true,
 
      // Custom webpack config for SW
      webpackCompilationPlugins: [
        new TerserPlugin({
          terserOptions: {
            compress: {
              drop_console: true
            }
          }
        })
      ]
    })
  ]
};

Performance Monitoring

Bundle Analysis

// webpack-bundle-analyzer
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
 
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false,
      reportFilename: 'bundle-report.html'
    })
  ]
};
 
// Package.json script
{
  "scripts": {
    "analyze": "npm run build && npx webpack-bundle-analyzer dist/static/js/*.js"
  }
}

Runtime Performance Monitoring

// Monitor JS parsing and execution time
function measureJavaScriptPerformance() {
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (entry.name.includes('.js')) {
        console.log('JS File:', entry.name);
        console.log('Parse Time:', entry.duration + 'ms');
        console.log('Transfer Size:', entry.transferSize + ' bytes');
 
        // Calculate compression ratio
        const compressionRatio = entry.encodedBodySize > 0
          ? (entry.transferSize / entry.encodedBodySize * 100).toFixed(1)
          : 'N/A';
        console.log('Compression:', compressionRatio + '%');
      }
    }
  });
 
  observer.observe({ entryTypes: ['resource'] });
}
 
// Measure JavaScript execution time
function measureExecutionTime(fn, label) {
  const start = performance.now();
  const result = fn();
  const end = performance.now();
 
  console.log(`${label}: ${(end - start).toFixed(2)}ms`);
  return result;
}

Security Considerations

Safe Minification Practices

// terser.config.js
module.exports = {
  compress: {
    // Don't remove function names needed for error reporting
    keep_fnames: true,
 
    // Don't remove function arguments (needed for some libraries)
    keep_fargs: true,
 
    // Be careful with unsafe optimizations
    unsafe: false,
    unsafe_comps: false,
    unsafe_math: false,
 
    // Don't optimize regular expressions aggressively
    unsafe_regexp: false
  },
 
  mangle: {
    // Don't mangle properties that might be accessed dynamically
    properties: {
      reserved: ['$', 'jQuery', 'API_KEY', 'CONFIG']
    }
  }
};

Source Maps for Production Debugging

// webpack.config.js
module.exports = {
  devtool: process.env.NODE_ENV === 'production'
    ? 'hidden-source-map'  // Generate maps but don't expose them
    : 'eval-source-map',
 
  optimization: {
    minimizer: [
      new TerserPlugin({
        sourceMap: true, // Generate source maps
        terserOptions: {
          // Keep function names for better error reporting
          keep_fnames: /^(API|Config|Utils)/
        }
      })
    ]
  }
};

Best Practices

  1. Automate in CI/CD: Never manually minify JavaScript files
  2. Environment-Specific: Only minify in production builds
  3. Source Maps: Always generate source maps for debugging
  4. Test After Minification: Ensure functionality remains intact
  5. Bundle Analysis: Regularly analyze bundle sizes and composition
  6. Dead Code Elimination: Remove unused code before minification
  7. Code Splitting: Split large bundles for better caching
  8. Monitor Performance: Track bundle sizes and loading times
  9. Security: Be cautious with aggressive minification options
  10. Backup Strategy: Keep unminified versions for debugging

Common Issues and Solutions

Broken Code After Minification

// Problem: Variable name collision
// Solution: Configure mangle options carefully
{
  mangle: {
    reserved: ['$', 'jQuery', 'API_KEY'], // Don't mangle these
    properties: {
      regex: /^_private/ // Only mangle private properties
    }
  }
}

Source Map Issues

// Solution: Proper source map configuration
{
  devtool: 'source-map',
  output: {
    sourceMapFilename: '[name].[contenthash].map'
  }
}

Third-party Library Issues

// Solution: Exclude problematic libraries from minification
{
  optimization: {
    minimizer: [
      new TerserPlugin({
        exclude: /node_modules\/(problematic-library)/
      })
    ]
  }
}

Support Notes

  • Minification output can differ by toolchain and target browser assumptions, so verify the real production bundle and source-map behavior.
  • Do not assume modern syntax can remain untransformed if an older target browser is still supported.

Verification

Automated Checks

  • Verify the behavior in the browser after the code change, not only in static analysis.
  • Inspect DevTools Network or Performance panels when the rule affects loading or execution order.
  • Test the primary user flow and one edge case triggered by the changed script path.

Manual Checks

  • Confirm the code still behaves correctly when the feature is delayed, lazy-loaded, or fails.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Verify that all JavaScript files are minified in production to reduce file size, remove comments, and optimize code for faster loading and execution.

Fix

Auto-fix issues

Configure your build system to minify JavaScript files using tools like Terser, UglifyJS, or built-in framework minification for production deployment.

Explain

Learn more

Explain how JavaScript minification improves website performance by reducing bundle sizes, eliminating dead code, and optimizing parsing speed.

Review

Code review

Review scripts, client components, and browser execution paths related to Minify all JavaScript files. Flag exact imports, event handlers, runtime side effects, or blocking operations that violate the rule, and state how the change should be verified in the browser.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Chrome DevTools
developer.chrome.comTool

Rules that often go hand-in-hand with this one.

Debounce and throttle event handlers

Use debounce or throttle for high-frequency events like scroll, resize, and input to improve performance.

JavaScript
Prevent common memory leak patterns

Identify and avoid the most common JavaScript memory leak sources: forgotten event listeners, retained DOM references, closures holding large objects, and uncleared timers.

JavaScript
Minify all CSS files

All CSS files are minified to reduce file size and improve page load performance.

CSS
Remove unused CSS rules

Unused CSS is removed to reduce bundle size and improve performance.

CSS

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385