Remove comments and debug code in production
Unnecessary code, comments, and debug elements are removed before deploying to production.
- Remove TODO, FIXME, DEBUG comments before production
- Keep accessibility and legal comments
- Configure build tools to strip comments automatically
- Review for sensitive data leaks in comments
Rule Details
Remove unnecessary code, comments, and debug elements before deploying to production to reduce file size and improve security.
Code Examples
Development Comments
<!-- ❌ Remove: Development comments -->
<!-- TODO: Fix this later -->
<!-- FIXME: This is a temporary solution -->
<!-- DEBUG: Testing responsive layout -->
<!-- This section needs refactoring -->
<!-- ✅ Keep: Important comments for production -->
<!-- Skip to main content link for accessibility -->
<a href="#main" class="skip-link">Skip to main content</a>
<!-- Critical above-the-fold styles -->
<style>
/* Critical CSS for initial page load */
</style>Debug Code and Testing Elements
<!-- ❌ Remove: Debug elements -->
<div class="debug-info" style="background: red;">
Debug: Current viewport width
</div>
<div id="test-element" data-test="debugging">
Test content for development
</div>
<!-- ❌ Remove: Console logs in inline scripts -->
<script>
console.log('Page loaded for debugging')
console.table(userData)
debugger; // Remove debugger statements
</script>
<!-- ✅ Clean production version -->
<script>
// Only production-ready code
initializeApp()
</script>Unused Markup and Dead Code
<!-- ❌ Remove: Commented out old code -->
<!--
<div class="old-layout">
<p>This was the old design</p>
</div>
-->
<!-- ❌ Remove: Unused elements -->
<div class="feature-not-implemented" style="display: none;">
Future feature placeholder
</div>
<!-- ❌ Remove: Empty or meaningless elements -->
<div></div>
<span class="unused"></span>
<p> </p>Why It Matters
Comments expose internal logic to attackers, increase file size, and can leak sensitive information like API endpoints, credentials, or system architecture.
Framework Examples
Next.js Production Build
// ❌ Development version
export default function HomePage() {
// TODO: Implement user preferences
const debugMode = true // Remove debug flags
return (
<div>
{/* DEBUG: Check responsive breakpoints */}
<div className={`container ${debugMode ? 'debug-borders' : ''}`}>
<h1>Welcome</h1>
{/* FIXME: Temporary hardcoded content */}
<p>This needs to be dynamic</p>
{debugMode && (
<div className="debug-panel">
<p>Debug info here</p>
</div>
)}
</div>
</div>
)
}
// ✅ Production version
export default function HomePage() {
return (
<div>
<div className="container">
<h1>Welcome</h1>
<p>Dynamic content from CMS</p>
</div>
</div>
)
}React Component Cleanup
// ❌ Development version with debug code
import React, { useState, useEffect } from 'react'
function ProductList({ products }) {
const [debugInfo, setDebugInfo] = useState(null)
useEffect(() => {
// Debug: Log component mounting
console.log('ProductList mounted with', products.length, 'products')
// TODO: Add error boundary
setDebugInfo({
timestamp: Date.now(),
productCount: products.length
})
}, [products])
return (
<div className="product-list">
{/* Development helper */}
{process.env.NODE_ENV === 'development' && (
<div className="debug-toolbar">
<button onClick={() => console.table(products)}>
Debug Products
</button>
</div>
)}
<h2>Products ({products.length})</h2>
{/* TEMP: Hardcoded featured product */}
<div className="featured-temp">
<p>Featured product placeholder</p>
</div>
{products.map(product => (
<div key={product.id} className="product-card">
<h3>{product.name}</h3>
<p>{product.description}</p>
{/* TODO: Add to cart functionality */}
</div>
))}
{/* Debug info display */}
{debugInfo && (
<pre className="debug-info">
{JSON.stringify(debugInfo, null, 2)}
</pre>
)}
</div>
)
}
// ✅ Clean production version
import React from 'react'
function ProductList({ products }) {
return (
<div className="product-list">
<h2>Products ({products.length})</h2>
{products.map(product => (
<div key={product.id} className="product-card">
<h3>{product.name}</h3>
<p>{product.description}</p>
<button className="add-to-cart">Add to Cart</button>
</div>
))}
</div>
)
}Vue.js Template Cleanup
<!-- ❌ Development version -->
<template>
<div class="user-profile">
<!-- DEBUG: Component state inspection -->
<div v-if="$store.state.debug" class="debug-panel">
<h4>Debug Info</h4>
<pre>{{ $data }}</pre>
</div>
<h1>{{ user.name }}</h1>
<!-- TODO: Add user preferences section -->
<!-- <UserPreferences :user="user" /> -->
<!-- TEMP: Mock data display -->
<div class="temp-content">
<p>Using temporary mock data</p>
</div>
<div class="user-details">
<p>Email: {{ user.email }}</p>
<!-- FIXME: Format date properly -->
<p>Joined: {{ user.createdAt }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'UserProfile',
props: ['user'],
mounted() {
// Debug logging
console.log('UserProfile mounted:', this.user)
// TODO: Track user profile views
// this.trackPageView()
}
}
</script>
<!-- ✅ Clean production version -->
<template>
<div class="user-profile">
<h1>{{ user.name }}</h1>
<UserPreferences :user="user" />
<div class="user-details">
<p>Email: {{ user.email }}</p>
<p>Joined: {{ formatDate(user.createdAt) }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'UserProfile',
props: ['user'],
methods: {
formatDate(date) {
return new Date(date).toLocaleDateString()
}
},
mounted() {
this.trackPageView()
}
}
</script>Build Tool Integration
Webpack Production Cleanup
// webpack.config.js
const webpack = require('webpack')
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
plugins: [
// Remove comments in production
new webpack.BannerPlugin({
banner: '/*! Built for production */',
test: /\.js$/
}),
// Remove console logs in production
...(process.env.NODE_ENV === 'production' ? [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
] : []),
],
optimization: {
minimize: process.env.NODE_ENV === 'production',
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // Remove console.* calls
drop_debugger: true, // Remove debugger statements
pure_funcs: ['console.log', 'console.info'], // Remove specific functions
},
mangle: true,
output: {
comments: false, // Remove comments
},
},
}),
],
},
}Vite Production Configuration
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
build: {
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
format: {
comments: false,
},
},
// Remove unused CSS
rollupOptions: {
treeshake: true,
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash', 'axios']
}
}
}
},
// Environment-specific settings
define: {
__DEV__: process.env.NODE_ENV !== 'production',
}
})PostCSS Comment Removal
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
// Remove comments in production
...(process.env.NODE_ENV === 'production' ? [
require('postcss-discard-comments')({
removeAll: true // Remove all comments
})
] : []),
require('cssnano')({
preset: 'default'
})
]
}Automated Cleanup Scripts
Pre-deployment Script
#!/bin/bash
# scripts/cleanup-for-production.sh
echo "🧹 Cleaning up for production deployment..."
# Remove debug files
find . -name "*.debug.js" -delete
find . -name "*.test.js" -delete
find . -name "*.spec.js" -delete
# Remove development-only directories
rm -rf .storybook/
rm -rf __tests__/
rm -rf coverage/
# Remove unnecessary files
rm -f .env.local
rm -f .env.development
rm -f webpack.dev.js
# Clean up package.json scripts (remove dev scripts)
node scripts/cleanup-package-json.js
echo "✅ Production cleanup complete!"Node.js Cleanup Script
// scripts/remove-debug-code.js
const fs = require('fs')
const path = require('path')
function removeDebugCode(filePath) {
let content = fs.readFileSync(filePath, 'utf8')
// Remove console.log statements
content = content.replace(/console\.log\([^)]*\);?\s*/g, '')
// Remove debugger statements
content = content.replace(/debugger;?\s*/g, '')
// Remove TODO/FIXME comments
content = content.replace(/\/\*[\s]*TODO:.*?\*\//gs, '')
content = content.replace(/\/\/[\s]*TODO:.*$/gm, '')
content = content.replace(/\/\*[\s]*FIXME:.*?\*\//gs, '')
content = content.replace(/\/\/[\s]*FIXME:.*$/gm, '')
// Remove debug blocks
content = content.replace(/\/\*[\s]*DEBUG[\s\S]*?END DEBUG[\s]*\*\//g, '')
fs.writeFileSync(filePath, content)
}
// Process all JavaScript files
function processDirectory(dir) {
const files = fs.readdirSync(dir)
files.forEach(file => {
const filePath = path.join(dir, file)
const stat = fs.statSync(filePath)
if (stat.isDirectory() && !file.startsWith('.') && file !== 'node_modules') {
processDirectory(filePath)
} else if (file.endsWith('.js') || file.endsWith('.jsx') || file.endsWith('.ts') || file.endsWith('.tsx')) {
removeDebugCode(filePath)
}
})
}
processDirectory('./src')
console.log('✅ Debug code removed from all source files')HTML Template Cleanup
// scripts/clean-html-templates.js
const fs = require('fs')
const glob = require('glob')
const { JSDOM } = require('jsdom')
glob('**/*.html', (err, files) => {
if (err) throw err
files.forEach(file => {
const html = fs.readFileSync(file, 'utf8')
const dom = new JSDOM(html)
const document = dom.window.document
// Remove elements with debug classes
const debugElements = document.querySelectorAll('.debug, .temp, [class*="debug"], [class*="temp"]')
debugElements.forEach(el => el.remove())
// Remove comment nodes
const walker = document.createTreeWalker(
document.body,
dom.window.NodeFilter.SHOW_COMMENT
)
const commentsToRemove = []
let node
while (node = walker.nextNode()) {
if (node.nodeValue.includes('TODO') ||
node.nodeValue.includes('FIXME') ||
node.nodeValue.includes('DEBUG')) {
commentsToRemove.push(node)
}
}
commentsToRemove.forEach(comment => comment.remove())
// Save cleaned HTML
fs.writeFileSync(file, dom.serialize())
})
console.log(`✅ Cleaned ${files.length} HTML files`)
})Security Benefits
Remove Sensitive Information
<!-- ❌ Don't leave sensitive info in production -->
<!-- Database connection: mongodb://user:password@localhost/myapp -->
<!-- API Key: sk-1234567890abcdef -->
<!-- Admin panel: /secret-admin-panel -->
<!-- ❌ Remove development credentials -->
<script>
const API_KEY = 'dev-key-12345' // Remove dev keys
const DEBUG_MODE = true // Remove debug flags
</script>
<!-- ✅ Use environment variables in production -->
<script>
const API_KEY = process.env.NEXT_PUBLIC_API_KEY
</script>Remove Development Endpoints
// ❌ Remove debug routes
app.get('/debug', (req, res) => {
res.json({
environment: process.env,
database: dbConnection.config,
users: allUsers // Don't expose user data
})
})
// ❌ Remove test endpoints
app.post('/test-payment', (req, res) => {
// Always processes without charging
res.json({ success: true })
})Performance Benefits
- Reduced File Size: Remove unnecessary bytes
- Faster Parsing: Less code to parse and execute
- Better Caching: Clean code caches more efficiently
- Improved SEO: Cleaner HTML structure
Tools and Automation
- Webpack/Vite: Automatic minification and dead code elimination
- Terser: Remove console logs and debug code
- PostCSS: Clean CSS comments and unused styles
- ESLint: Detect console.log and debugger statements
- Prettier: Consistent code formatting
- Pre-commit Hooks: Prevent debug code from being committed
Best Practices
- Use Environment Variables: Different configs for dev/prod
- Automate Cleanup: Build process handles code cleaning
- Code Reviews: Check for leftover debug code
- Linting Rules: Prevent console.log in production code
- Source Maps: Keep debugging capability without exposing source
- Feature Flags: Control features without code comments
- Staging Environment: Final check before production
Standards
- Use MDN: HTML as the standard for the final rendered HTML and browser-facing behavior.
- Use WHATWG HTML Living Standard as the standard for the final rendered HTML and browser-facing behavior.
Verification
Automated Checks
- Inspect the final rendered HTML in the browser or page source to confirm the rule is satisfied.
- Validate the affected markup with browser tooling or an HTML validator where appropriate.
- Test one representative route or template that uses the pattern.
- Re-check shared components that emit the same markup so the fix is consistent.
Manual Checks
- Verify the rendered browser behavior manually on representative routes and supported browsers so the user-facing outcome matches the rule.
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
Review this HTML code for unnecessary comments, debug code, console logs, and temporary markup that should be removed before production deployment.
Fix
Auto-fix issues
Remove all development comments, debug code, unused markup, and temporary elements from the HTML before deploying to production.
Explain
Learn more
Explain why cleaning up code before production is important for security, performance, and professional presentation of web applications.
Review
Code review
Review templates, server-rendered HTML, and shared components that output markup related to Remove comments and debug code in production. Flag exact elements, attributes, and routes where the rendered HTML violates the rule.