Files
aperonight/docs/application-optimization.md
kbe 17e6711299 Wip on homepage.
Add documentation how to optimize code size in production.
2025-08-16 22:45:27 +02:00

4.3 KiB

Application.js Size Optimization Guide

Current Issue

The application.js bundle is 1.4MB (2.3MB with source maps), which is significantly larger than recommended.

Root Causes

  1. Single bundle includes everything: All dependencies, React, controllers, and components
  2. No code splitting: Everything is bundled into one file
  3. Development dependencies: Alpine.js and other dev tools included
  4. No minification/optimization: Source maps and uncompressed code

Optimization Strategies

Create separate bundles for different parts of the application:

Update package.json build scripts:

{
  "scripts": {
    "build": "npm run build:main && npm run build:components",
    "build:main": "esbuild app/javascript/application.js --bundle --minify --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets",
    "build:components": "esbuild app/javascript/components/*.* --bundle --minify --format=esm --outdir=app/assets/builds/components --public-path=/assets --loader:.js=jsx",
    "build:css": "postcss ./app/assets/stylesheets/application.postcss.css -o ./app/assets/builds/application.css"
  }
}

2. Remove Unused Dependencies

package.json optimization:

{
  "dependencies": {
    "@hotwired/stimulus": "^3.2.2",
    "@hotwired/turbo-rails": "^8.0.13",
    "@radix-ui/react-slot": "^1.2.3",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4.1.4",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "esbuild": "^0.25.4",
    "postcss": "^8.5.3",
    "tailwind-merge": "^3.3.1",
    "tailwindcss": "^4.1.4",
    "tailwindcss-animate": "^1.0.7"
  }
}

Remove these from devDependencies:

  • alpinejs - if not used
  • @types/alpinejs - if Alpine.js removed
  • cssnano - if using Tailwind's built-in minification
  • pm2 - production deployment tool

3. Dynamic Imports (Code Splitting)

Update application.js:

// Instead of importing everything statically
import "@hotwired/turbo-rails"
import "./controllers"

// Use dynamic imports for heavy components
const loadComponent = async (componentName) => {
  const { default: component } = await import(`./components/${componentName}`)
  return component
}

4. Tree Shaking & Minification

Enhanced build command:

{
  "build": "esbuild app/javascript/application.js --bundle --minify --tree-shaking --drop:console --drop:debugger --sourcemap=external --format=esm --outdir=app/assets/builds --public-path=/assets"
}

5. Separate Vendor Bundle

Create vendor.js:

// app/javascript/vendor.js
import "react"
import "react-dom"
import "@radix-ui/react-slot"

Update build to create vendor bundle:

{
  "build:vendor": "esbuild app/javascript/vendor.js --bundle --minify --format=esm --outdir=app/assets/builds --public-path=/assets",
  "build:app": "esbuild app/javascript/application.js --bundle --minify --external:react --external:react-dom --format=esm --outdir=app/assets/builds --public-path=/assets"
}

6. Conditional Loading

Lazy load heavy components:

// app/javascript/application.js
if (document.querySelector('[data-controller="shadcn-test"]')) {
  import('./controllers/shadcn_test_controller')
}

7. Production Optimization Checklist

Step 1: Analyze bundle size

npm install --save-dev webpack-bundle-analyzer
npx esbuild app/javascript/application.js --bundle --analyze

Step 2: Implement optimizations

# Remove unused dependencies
npm uninstall alpinejs @types/alpinejs cssnano pm2

# Update build scripts
npm run build

Step 3: Verify size reduction Should reduce from 1.4MB to ~200-400KB

Quick Fix Commands

# 1. Remove Alpine.js (if unused)
npm uninstall alpinejs @types/alpinejs

# 2. Update build with optimization
npm install --save-dev esbuild@latest

# 3. Modify package.json scripts
# (Copy the optimized scripts above)

# 4. Build with optimization
npm run build

Expected Results

  • Before: 1.4MB application.js
  • After: 200-400KB with code splitting
  • Vendor bundle: ~100KB (cached)
  • App bundle: ~100-300KB (dynamic)

Monitoring

Add bundle size monitoring to CI/CD:

{
  "size-limits": {
    "app/assets/builds/application.js": "500kb",
    "app/assets/builds/application.css": "50kb"
  }
}