4.3 KiB
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
- Single bundle includes everything: All dependencies, React, controllers, and components
- No code splitting: Everything is bundled into one file
- Development dependencies: Alpine.js and other dev tools included
- No minification/optimization: Source maps and uncompressed code
Optimization Strategies
1. Split Bundles (Recommended)
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 removedcssnano- if using Tailwind's built-in minificationpm2- 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"
}
}