Loading...
Automatically compiles SCSS/Sass files to CSS when they are modified
{
"hookConfig": {
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/scss-auto-compiler.sh",
"matchers": [
"write",
"edit"
]
}
}
},
"scriptContent": "#!/bin/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 this is a SCSS or Sass file\nif [[ \"$FILE_PATH\" == *.scss ]] || [[ \"$FILE_PATH\" == *.sass ]]; then\n echo \"π¨ SCSS Auto-Compiler - Processing stylesheet...\"\n echo \"π File: $FILE_PATH\"\n \n # Check if file exists\n if [ ! -f \"$FILE_PATH\" ]; then\n echo \"β οΈ File not found: $FILE_PATH\"\n exit 1\n fi\n \n # Determine output CSS file path\n if [[ \"$FILE_PATH\" == *.scss ]]; then\n CSS_OUTPUT=\"${FILE_PATH%.scss}.css\"\n MAP_OUTPUT=\"${FILE_PATH%.scss}.css.map\"\n else # .sass file\n CSS_OUTPUT=\"${FILE_PATH%.sass}.css\"\n MAP_OUTPUT=\"${FILE_PATH%.sass}.css.map\"\n fi\n \n echo \"π Output: $CSS_OUTPUT\"\n \n # Check if Sass compiler is available\n if command -v sass >/dev/null 2>&1; then\n SASS_CMD=\"sass\"\n elif command -v npx >/dev/null 2>&1 && npx sass --version >/dev/null 2>&1; then\n SASS_CMD=\"npx sass\"\n elif command -v node-sass >/dev/null 2>&1; then\n SASS_CMD=\"node-sass\"\n echo \"βΉοΈ Using node-sass (consider upgrading to Dart Sass)\"\n else\n echo \"β οΈ No Sass compiler found\"\n echo \"π‘ Install options:\"\n echo \" β’ npm install -g sass (Dart Sass - recommended)\"\n echo \" β’ npm install sass (project-local)\"\n echo \" β’ brew install sass/sass/sass (macOS)\"\n exit 1\n fi\n \n echo \"π§ Compiling with $SASS_CMD...\"\n \n # Compile SCSS/Sass to CSS with source maps\n if [[ \"$SASS_CMD\" == \"node-sass\" ]]; then\n # node-sass syntax\n if node-sass \"$FILE_PATH\" \"$CSS_OUTPUT\" --source-map true --source-map-contents; then\n echo \"β
SCSS compiled successfully with node-sass\"\n else\n echo \"β SCSS compilation failed\"\n exit 1\n fi\n else\n # Dart Sass syntax\n if $SASS_CMD \"$FILE_PATH\" \"$CSS_OUTPUT\" --source-map; then\n echo \"β
SCSS compiled successfully\"\n else\n echo \"β SCSS compilation failed\"\n exit 1\n fi\n fi\n \n # Check output file size\n if [ -f \"$CSS_OUTPUT\" ]; then\n CSS_SIZE=$(stat -f%z \"$CSS_OUTPUT\" 2>/dev/null || stat -c%s \"$CSS_OUTPUT\" 2>/dev/null || echo \"unknown\")\n echo \"π Generated CSS: ${CSS_SIZE} bytes\"\n \n # Check for source map\n if [ -f \"$MAP_OUTPUT\" ]; then\n echo \"πΊοΈ Source map: $MAP_OUTPUT\"\n fi\n fi\n \n # Additional analysis\n echo \"\"\n echo \"π SCSS Analysis:\"\n \n # Count SCSS features used\n if grep -q '@import\\|@use' \"$FILE_PATH\" 2>/dev/null; then\n IMPORT_COUNT=$(grep -c '@import\\|@use' \"$FILE_PATH\" 2>/dev/null || echo 0)\n echo \" β’ Imports/Uses: $IMPORT_COUNT\"\n fi\n \n if grep -q '@mixin' \"$FILE_PATH\" 2>/dev/null; then\n MIXIN_COUNT=$(grep -c '@mixin' \"$FILE_PATH\" 2>/dev/null || echo 0)\n echo \" β’ Mixins defined: $MIXIN_COUNT\"\n fi\n \n if grep -q '@include' \"$FILE_PATH\" 2>/dev/null; then\n INCLUDE_COUNT=$(grep -c '@include' \"$FILE_PATH\" 2>/dev/null || echo 0)\n echo \" β’ Mixin includes: $INCLUDE_COUNT\"\n fi\n \n if grep -q '\\$[a-zA-Z]' \"$FILE_PATH\" 2>/dev/null; then\n echo \" β’ π‘ Variables detected - using SCSS features\"\n fi\n \n if grep -q '&' \"$FILE_PATH\" 2>/dev/null; then\n echo \" β’ π‘ Nested selectors detected\"\n fi\n \n # Check for common issues\n echo \"\"\n echo \"π Code Quality Check:\"\n \n if grep -q '!important' \"$FILE_PATH\" 2>/dev/null; then\n IMPORTANT_COUNT=$(grep -c '!important' \"$FILE_PATH\" 2>/dev/null || echo 0)\n echo \" β’ β οΈ !important usage: $IMPORTANT_COUNT (consider refactoring)\"\n fi\n \n if grep -q 'color: #[0-9a-fA-F]\\{3,6\\}' \"$FILE_PATH\" 2>/dev/null; then\n echo \" β’ π‘ Consider using CSS custom properties for colors\"\n fi\n \n echo \"\"\n echo \"π‘ SCSS Development Tips:\"\n echo \" β’ Use @use instead of @import for better performance\"\n echo \" β’ Organize styles with partials (_filename.scss)\"\n echo \" β’ Use mixins for reusable style patterns\"\n echo \" β’ Leverage SCSS variables for consistent theming\"\n echo \" β’ Use nested selectors sparingly (max 3-4 levels)\"\n \n echo \"\"\n echo \"π― SCSS compilation complete!\"\n \nelse\n echo \"βΉοΈ File is not a SCSS/Sass file: $FILE_PATH\"\nfi\n\nexit 0"
}.claude/hooks/~/.claude/hooks/{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/scss-auto-compiler.sh",
"matchers": [
"write",
"edit"
]
}
}
}#!/bin/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 this is a SCSS or Sass file
if [[ "$FILE_PATH" == *.scss ]] || [[ "$FILE_PATH" == *.sass ]]; then
echo "π¨ SCSS Auto-Compiler - Processing stylesheet..."
echo "π File: $FILE_PATH"
# Check if file exists
if [ ! -f "$FILE_PATH" ]; then
echo "β οΈ File not found: $FILE_PATH"
exit 1
fi
# Determine output CSS file path
if [[ "$FILE_PATH" == *.scss ]]; then
CSS_OUTPUT="${FILE_PATH%.scss}.css"
MAP_OUTPUT="${FILE_PATH%.scss}.css.map"
else # .sass file
CSS_OUTPUT="${FILE_PATH%.sass}.css"
MAP_OUTPUT="${FILE_PATH%.sass}.css.map"
fi
echo "π Output: $CSS_OUTPUT"
# Check if Sass compiler is available
if command -v sass >/dev/null 2>&1; then
SASS_CMD="sass"
elif command -v npx >/dev/null 2>&1 && npx sass --version >/dev/null 2>&1; then
SASS_CMD="npx sass"
elif command -v node-sass >/dev/null 2>&1; then
SASS_CMD="node-sass"
echo "βΉοΈ Using node-sass (consider upgrading to Dart Sass)"
else
echo "β οΈ No Sass compiler found"
echo "π‘ Install options:"
echo " β’ npm install -g sass (Dart Sass - recommended)"
echo " β’ npm install sass (project-local)"
echo " β’ brew install sass/sass/sass (macOS)"
exit 1
fi
echo "π§ Compiling with $SASS_CMD..."
# Compile SCSS/Sass to CSS with source maps
if [[ "$SASS_CMD" == "node-sass" ]]; then
# node-sass syntax
if node-sass "$FILE_PATH" "$CSS_OUTPUT" --source-map true --source-map-contents; then
echo "β
SCSS compiled successfully with node-sass"
else
echo "β SCSS compilation failed"
exit 1
fi
else
# Dart Sass syntax
if $SASS_CMD "$FILE_PATH" "$CSS_OUTPUT" --source-map; then
echo "β
SCSS compiled successfully"
else
echo "β SCSS compilation failed"
exit 1
fi
fi
# Check output file size
if [ -f "$CSS_OUTPUT" ]; then
CSS_SIZE=$(stat -f%z "$CSS_OUTPUT" 2>/dev/null || stat -c%s "$CSS_OUTPUT" 2>/dev/null || echo "unknown")
echo "π Generated CSS: ${CSS_SIZE} bytes"
# Check for source map
if [ -f "$MAP_OUTPUT" ]; then
echo "πΊοΈ Source map: $MAP_OUTPUT"
fi
fi
# Additional analysis
echo ""
echo "π SCSS Analysis:"
# Count SCSS features used
if grep -q '@import\|@use' "$FILE_PATH" 2>/dev/null; then
IMPORT_COUNT=$(grep -c '@import\|@use' "$FILE_PATH" 2>/dev/null || echo 0)
echo " β’ Imports/Uses: $IMPORT_COUNT"
fi
if grep -q '@mixin' "$FILE_PATH" 2>/dev/null; then
MIXIN_COUNT=$(grep -c '@mixin' "$FILE_PATH" 2>/dev/null || echo 0)
echo " β’ Mixins defined: $MIXIN_COUNT"
fi
if grep -q '@include' "$FILE_PATH" 2>/dev/null; then
INCLUDE_COUNT=$(grep -c '@include' "$FILE_PATH" 2>/dev/null || echo 0)
echo " β’ Mixin includes: $INCLUDE_COUNT"
fi
if grep -q '\$[a-zA-Z]' "$FILE_PATH" 2>/dev/null; then
echo " β’ π‘ Variables detected - using SCSS features"
fi
if grep -q '&' "$FILE_PATH" 2>/dev/null; then
echo " β’ π‘ Nested selectors detected"
fi
# Check for common issues
echo ""
echo "π Code Quality Check:"
if grep -q '!important' "$FILE_PATH" 2>/dev/null; then
IMPORTANT_COUNT=$(grep -c '!important' "$FILE_PATH" 2>/dev/null || echo 0)
echo " β’ β οΈ !important usage: $IMPORTANT_COUNT (consider refactoring)"
fi
if grep -q 'color: #[0-9a-fA-F]\{3,6\}' "$FILE_PATH" 2>/dev/null; then
echo " β’ π‘ Consider using CSS custom properties for colors"
fi
echo ""
echo "π‘ SCSS Development Tips:"
echo " β’ Use @use instead of @import for better performance"
echo " β’ Organize styles with partials (_filename.scss)"
echo " β’ Use mixins for reusable style patterns"
echo " β’ Leverage SCSS variables for consistent theming"
echo " β’ Use nested selectors sparingly (max 3-4 levels)"
echo ""
echo "π― SCSS compilation complete!"
else
echo "βΉοΈ File is not a SCSS/Sass file: $FILE_PATH"
fi
exit 0Compilation fails with 'sass command not found'
Install Dart Sass globally with `npm install -g sass` or locally `npm install sass`, then restart terminal. For project-specific, hook uses `npx sass` which auto-detects local installations.
Source maps not generated in output directory
Ensure write permissions on output directory. Hook generates maps automatically: `$SASS_CMD "$FILE_PATH" "$CSS_OUTPUT" --source-map`. Check if MAP_OUTPUT path is writable and not gitignored.
Hook compiles partials creating unwanted CSS
Add early exit for partials: `if [[ "$(basename "$FILE_PATH")" == _* ]]; then exit 0; fi` before compilation. SCSS partials (prefixed with _) shouldn't compile to separate CSS files.
node-sass deprecated warnings appear in output
Migrate to Dart Sass: uninstall `npm uninstall node-sass`, install `npm install sass`. Hook automatically prefers Dart Sass over node-sass when both are available and shows migration notice.
Cannot parse @import vs @use distinction
Hook uses regex `grep -q '@import\|@use'` to detect both. For separate counts, use: `IMPORT=$(grep -c '@import' ...)` and `USE=$(grep -c '@use' ...)` to distinguish modern @use from legacy @import.
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