Loading...
Detects unused CSS selectors when stylesheets are modified to keep CSS lean
{
"hookConfig": {
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/css-unused-selector-detector.sh",
"matchers": [
"write",
"edit"
]
}
}
},
"scriptContent": "#!/usr/bin/env bash\n\n# Read the tool input from stdin\nINPUT=$(cat)\nTOOL_NAME=$(echo \"$INPUT\" | jq -r '.tool_name')\nFILE_PATH=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path // \"\"')\n\nif [ -z \"$FILE_PATH\" ]; then\n exit 0\nfi\n\n# Check if it's a CSS/SCSS file\nif [[ \"$FILE_PATH\" == *.css ]] || [[ \"$FILE_PATH\" == *.scss ]] || [[ \"$FILE_PATH\" == *.sass ]]; then\n echo \"๐ Analyzing CSS file for unused selectors: $FILE_PATH\" >&2\n \n # Check if file exists\n if [ ! -f \"$FILE_PATH\" ]; then\n echo \"๐ CSS file does not exist yet, skipping analysis\" >&2\n exit 0\n fi\n \n # Get original file size\n ORIGINAL_LINES=$(wc -l < \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n ORIGINAL_SIZE=$(wc -c < \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n \n echo \"๐ Original CSS: $ORIGINAL_LINES lines, $ORIGINAL_SIZE bytes\" >&2\n \n # Try PurgeCSS if available\n if command -v npx &> /dev/null && npx purgecss --version &> /dev/null; then\n echo \"๐งน Running PurgeCSS analysis...\" >&2\n \n # Create analysis directory\n mkdir -p css-analysis\n \n # Run PurgeCSS with multiple content patterns\n if npx purgecss --css \"$FILE_PATH\" \\\n --content './src/**/*.{html,js,jsx,ts,tsx,vue,svelte}' \\\n --content './**/*.{html,js,jsx,ts,tsx,vue,svelte}' \\\n --output ./css-analysis/ 2>/dev/null; then\n \n # Analyze results\n PURGED_FILE=\"./css-analysis/$(basename \"$FILE_PATH\")\"\n if [ -f \"$PURGED_FILE\" ]; then\n PURGED_LINES=$(wc -l < \"$PURGED_FILE\" 2>/dev/null || echo \"0\")\n PURGED_SIZE=$(wc -c < \"$PURGED_FILE\" 2>/dev/null || echo \"0\")\n \n SAVED_LINES=$((ORIGINAL_LINES - PURGED_LINES))\n SAVED_SIZE=$((ORIGINAL_SIZE - PURGED_SIZE))\n REDUCTION_PERCENT=$((SAVED_SIZE * 100 / ORIGINAL_SIZE))\n \n echo \"๐ Optimized CSS: $PURGED_LINES lines, $PURGED_SIZE bytes\" >&2\n echo \"โ
Potential savings: $SAVED_LINES lines, $SAVED_SIZE bytes ($REDUCTION_PERCENT% reduction)\" >&2\n echo \"๐ Check css-analysis/$(basename \"$FILE_PATH\") for optimized version\" >&2\n else\n echo \"โ ๏ธ PurgeCSS analysis completed but no output generated\" >&2\n fi\n else\n echo \"โ PurgeCSS analysis failed - check content paths\" >&2\n fi\n else\n echo \"๐ก Install PurgeCSS (npm install -g purgecss) for CSS optimization analysis\" >&2\n \n # Basic analysis without PurgeCSS\n SELECTOR_COUNT=$(grep -o '[.#][a-zA-Z][-a-zA-Z0-9_]*' \"$FILE_PATH\" 2>/dev/null | sort -u | wc -l || echo \"0\")\n echo \"๐ Found $SELECTOR_COUNT unique CSS selectors in file\" >&2\n fi\n \n echo \"โ
CSS analysis completed for $FILE_PATH\" >&2\nelse\n echo \"File $FILE_PATH is not a CSS/SCSS file, skipping analysis\" >&2\nfi\n\nexit 0"
}.claude/hooks/~/.claude/hooks/{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/css-unused-selector-detector.sh",
"matchers": [
"write",
"edit"
]
}
}
}#!/usr/bin/env bash
# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# Check if it's a CSS/SCSS file
if [[ "$FILE_PATH" == *.css ]] || [[ "$FILE_PATH" == *.scss ]] || [[ "$FILE_PATH" == *.sass ]]; then
echo "๐ Analyzing CSS file for unused selectors: $FILE_PATH" >&2
# Check if file exists
if [ ! -f "$FILE_PATH" ]; then
echo "๐ CSS file does not exist yet, skipping analysis" >&2
exit 0
fi
# Get original file size
ORIGINAL_LINES=$(wc -l < "$FILE_PATH" 2>/dev/null || echo "0")
ORIGINAL_SIZE=$(wc -c < "$FILE_PATH" 2>/dev/null || echo "0")
echo "๐ Original CSS: $ORIGINAL_LINES lines, $ORIGINAL_SIZE bytes" >&2
# Try PurgeCSS if available
if command -v npx &> /dev/null && npx purgecss --version &> /dev/null; then
echo "๐งน Running PurgeCSS analysis..." >&2
# Create analysis directory
mkdir -p css-analysis
# Run PurgeCSS with multiple content patterns
if npx purgecss --css "$FILE_PATH" \
--content './src/**/*.{html,js,jsx,ts,tsx,vue,svelte}' \
--content './**/*.{html,js,jsx,ts,tsx,vue,svelte}' \
--output ./css-analysis/ 2>/dev/null; then
# Analyze results
PURGED_FILE="./css-analysis/$(basename "$FILE_PATH")"
if [ -f "$PURGED_FILE" ]; then
PURGED_LINES=$(wc -l < "$PURGED_FILE" 2>/dev/null || echo "0")
PURGED_SIZE=$(wc -c < "$PURGED_FILE" 2>/dev/null || echo "0")
SAVED_LINES=$((ORIGINAL_LINES - PURGED_LINES))
SAVED_SIZE=$((ORIGINAL_SIZE - PURGED_SIZE))
REDUCTION_PERCENT=$((SAVED_SIZE * 100 / ORIGINAL_SIZE))
echo "๐ Optimized CSS: $PURGED_LINES lines, $PURGED_SIZE bytes" >&2
echo "โ
Potential savings: $SAVED_LINES lines, $SAVED_SIZE bytes ($REDUCTION_PERCENT% reduction)" >&2
echo "๐ Check css-analysis/$(basename "$FILE_PATH") for optimized version" >&2
else
echo "โ ๏ธ PurgeCSS analysis completed but no output generated" >&2
fi
else
echo "โ PurgeCSS analysis failed - check content paths" >&2
fi
else
echo "๐ก Install PurgeCSS (npm install -g purgecss) for CSS optimization analysis" >&2
# Basic analysis without PurgeCSS
SELECTOR_COUNT=$(grep -o '[.#][a-zA-Z][-a-zA-Z0-9_]*' "$FILE_PATH" 2>/dev/null | sort -u | wc -l || echo "0")
echo "๐ Found $SELECTOR_COUNT unique CSS selectors in file" >&2
fi
echo "โ
CSS analysis completed for $FILE_PATH" >&2
else
echo "File $FILE_PATH is not a CSS/SCSS file, skipping analysis" >&2
fi
exit 0PurgeCSS not detecting any unused selectors in CSS
Verify content paths match your project structure. Update --content patterns to include all HTML/JSX/TSX files. Check PurgeCSS config safelist if critical selectors are protected.
PostToolUse hook only runs for write, not edit operations
Add both matchers to hook config: matchers: ['write', 'edit']. Verify tool_name extraction from stdin matches expected values. Test with echo to debug tool input parsing.
css-analysis directory not created or files missing
Check write permissions in project root. Ensure mkdir -p succeeds without errors. Verify PurgeCSS output path is writable. Check disk space if directory creation fails silently.
PurgeCSS removes critical CSS framework classes
Add safelist patterns to PurgeCSS config for framework classes. Use safelist: [/^btn-/, /^nav-/] syntax. Consider extracting framework CSS to separate file excluded from purging.
No output generated message despite PurgeCSS success
Check PURGED_FILE path construction matches PurgeCSS output. Verify basename command extracts correct filename. Ensure output directory exists before PurgeCSS runs with mkdir -p.
Loading reviews...
Join our community of Claude power users. No spam, unsubscribe anytime.
Automated accessibility testing and compliance checking for web applications following WCAG guidelines
Automatically generates or updates API documentation when endpoint files are modified
Automatically formats code files after Claude writes or edits them using Prettier, Black, or other formatters