Loading...
Analyzes Next.js page routes and generates a route map when pages are added or modified
{
"hookConfig": {
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/nextjs-route-analyzer.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 this is a Next.js page, component, or route file\nif [[ \"$FILE_PATH\" == *pages/*.* ]] || [[ \"$FILE_PATH\" == *app/*.* ]] || [[ \"$FILE_PATH\" == *src/pages/*.* ]] || [[ \"$FILE_PATH\" == *src/app/*.* ]]; then\n echo \"πΊοΈ Next.js Route Analysis for: $(basename \"$FILE_PATH\")\" >&2\n \n # Initialize analysis counters\n TOTAL_ROUTES=0\n STATIC_ROUTES=0\n DYNAMIC_ROUTES=0\n API_ROUTES=0\n CATCH_ALL_ROUTES=0\n ERRORS=0\n WARNINGS=0\n \n # Function to report analysis results\n report_analysis() {\n local level=\"$1\"\n local message=\"$2\"\n \n case \"$level\" in\n \"ERROR\")\n echo \"β ERROR: $message\" >&2\n ERRORS=$((ERRORS + 1))\n ;;\n \"WARNING\")\n echo \"β οΈ WARNING: $message\" >&2\n WARNINGS=$((WARNINGS + 1))\n ;;\n \"INFO\")\n echo \"βΉοΈ INFO: $message\" >&2\n ;;\n \"FOUND\")\n echo \"β
FOUND: $message\" >&2\n ;;\n esac\n }\n \n # Detect Next.js project structure\n PROJECT_ROOT=\".\"\n PAGES_DIR=\"\"\n APP_DIR=\"\"\n SRC_PAGES_DIR=\"\"\n SRC_APP_DIR=\"\"\n \n # Find project root and routing directories\n if [ -f \"./package.json\" ]; then\n # Check if this is a Next.js project\n if grep -q '\"next\"' \"./package.json\" 2>/dev/null; then\n echo \" π¦ Next.js project detected\" >&2\n \n # Check for different routing structures\n [ -d \"./pages\" ] && PAGES_DIR=\"./pages\"\n [ -d \"./app\" ] && APP_DIR=\"./app\"\n [ -d \"./src/pages\" ] && SRC_PAGES_DIR=\"./src/pages\"\n [ -d \"./src/app\" ] && SRC_APP_DIR=\"./src/app\"\n \n if [ -n \"$APP_DIR\" ] || [ -n \"$SRC_APP_DIR\" ]; then\n echo \" π§ App Router structure detected\" >&2\n fi\n \n if [ -n \"$PAGES_DIR\" ] || [ -n \"$SRC_PAGES_DIR\" ]; then\n echo \" π Pages Router structure detected\" >&2\n fi\n else\n report_analysis \"WARNING\" \"Not a Next.js project (no Next.js dependency found)\"\n fi\n else\n report_analysis \"WARNING\" \"No package.json found - may not be in project root\"\n fi\n \n # Create temporary files for route analysis\n ROUTES_FILE=\"/tmp/nextjs_routes_$$\"\n API_ROUTES_FILE=\"/tmp/nextjs_api_routes_$$\"\n ROUTE_MAP_FILE=\"/tmp/nextjs_route_map_$$\"\n \n echo \"π Analyzing route structure...\" >&2\n \n # Function to analyze route type\n analyze_route_type() {\n local route_path=\"$1\"\n local file_path=\"$2\"\n \n # Check if it's an API route\n if [[ \"$file_path\" == *\"/api/\"* ]] || [[ \"$route_path\" == *\"/api/\"* ]]; then\n API_ROUTES=$((API_ROUTES + 1))\n echo \"api|$route_path|$file_path\" >> \"$API_ROUTES_FILE\"\n return\n fi\n \n # Check route complexity\n if [[ \"$route_path\" == *\"[...\"* ]]; then\n # Catch-all route\n CATCH_ALL_ROUTES=$((CATCH_ALL_ROUTES + 1))\n echo \"catch-all|$route_path|$file_path\" >> \"$ROUTES_FILE\"\n elif [[ \"$route_path\" == *\"[\"* ]]; then\n # Dynamic route\n DYNAMIC_ROUTES=$((DYNAMIC_ROUTES + 1))\n echo \"dynamic|$route_path|$file_path\" >> \"$ROUTES_FILE\"\n else\n # Static route\n STATIC_ROUTES=$((STATIC_ROUTES + 1))\n echo \"static|$route_path|$file_path\" >> \"$ROUTES_FILE\"\n fi\n }\n \n # Function to convert file path to route\n file_to_route() {\n local file_path=\"$1\"\n local base_dir=\"$2\"\n \n # Remove base directory and file extension\n local route=$(echo \"$file_path\" | sed \"s|^$base_dir||\" | sed 's|\\\\.[jt]sx\\\\?$||')\n \n # Handle special Next.js file names\n route=$(echo \"$route\" | sed 's|/page$||') # Remove /page suffix\n route=$(echo \"$route\" | sed 's|/route$||') # Remove /route suffix\n route=$(echo \"$route\" | sed 's|/index$||') # Remove /index suffix\n \n # Convert empty route to root\n [ -z \"$route\" ] && route=\"/\"\n \n # Ensure route starts with /\n [[ \"$route\" != /* ]] && route=\"/$route\"\n \n echo \"$route\"\n }\n \n # Analyze Pages Router (if exists)\n for pages_dir in \"$PAGES_DIR\" \"$SRC_PAGES_DIR\"; do\n if [ -n \"$pages_dir\" ] && [ -d \"$pages_dir\" ]; then\n echo \" π Analyzing Pages Router in $pages_dir...\" >&2\n \n # Find all page files\n find \"$pages_dir\" -type f \\( -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.ts\" -o -name \"*.tsx\" \\) 2>/dev/null | while read -r file; do\n if [ -f \"$file\" ]; then\n route=$(file_to_route \"$file\" \"$pages_dir\")\n analyze_route_type \"$route\" \"$file\"\n echo \" π $route <- $file\" >&2\n fi\n done\n fi\n done\n \n # Analyze App Router (if exists)\n for app_dir in \"$APP_DIR\" \"$SRC_APP_DIR\"; do\n if [ -n \"$app_dir\" ] && [ -d \"$app_dir\" ]; then\n echo \" π§ Analyzing App Router in $app_dir...\" >&2\n \n # Find page.tsx/jsx and route.tsx/jsx files\n find \"$app_dir\" -type f \\( -name \"page.js\" -o -name \"page.jsx\" -o -name \"page.ts\" -o -name \"page.tsx\" -o -name \"route.js\" -o -name \"route.jsx\" -o -name \"route.ts\" -o -name \"route.tsx\" \\) 2>/dev/null | while read -r file; do\n if [ -f \"$file\" ]; then\n route=$(file_to_route \"$file\" \"$app_dir\")\n analyze_route_type \"$route\" \"$file\"\n echo \" π $route <- $file\" >&2\n fi\n done\n \n # Find layout files\n find \"$app_dir\" -type f \\( -name \"layout.js\" -o -name \"layout.jsx\" -o -name \"layout.ts\" -o -name \"layout.tsx\" \\) 2>/dev/null | while read -r file; do\n if [ -f \"$file\" ]; then\n layout_path=$(echo \"$file\" | sed \"s|^$app_dir||\" | sed 's|/layout\\\\.[jt]sx\\\\?$||')\n [ -z \"$layout_path\" ] && layout_path=\"/\"\n [[ \"$layout_path\" != /* ]] && layout_path=\"/$layout_path\"\n echo \" π¨ Layout: $layout_path <- $file\" >&2\n fi\n done\n fi\n done\n \n # Calculate totals\n TOTAL_ROUTES=$((STATIC_ROUTES + DYNAMIC_ROUTES + CATCH_ALL_ROUTES))\n \n # Generate route analysis report\n echo \"\" >&2\n echo \"π Route Analysis Results:\" >&2\n echo \"=========================\" >&2\n echo \" π Total Routes: $TOTAL_ROUTES\" >&2\n echo \" π Static Routes: $STATIC_ROUTES\" >&2\n echo \" π§ Dynamic Routes: $DYNAMIC_ROUTES\" >&2\n echo \" π Catch-all Routes: $CATCH_ALL_ROUTES\" >&2\n echo \" π API Routes: $API_ROUTES\" >&2\n \n # Route complexity analysis\n if [ \"$TOTAL_ROUTES\" -eq 0 ]; then\n report_analysis \"WARNING\" \"No routes found in the project\"\n elif [ \"$TOTAL_ROUTES\" -gt 50 ]; then\n report_analysis \"INFO\" \"Large application with $TOTAL_ROUTES routes\"\n else\n report_analysis \"INFO\" \"Application has $TOTAL_ROUTES routes\"\n fi\n \n # API route analysis\n if [ \"$API_ROUTES\" -gt 0 ]; then\n report_analysis \"FOUND\" \"$API_ROUTES API endpoints detected\"\n \n if [ -f \"$API_ROUTES_FILE\" ]; then\n echo \" π API Endpoints:\" >&2\n cat \"$API_ROUTES_FILE\" | while IFS='|' read -r type route file; do\n echo \" β’ $route\" >&2\n done\n fi\n fi\n \n # Dynamic route analysis\n if [ \"$DYNAMIC_ROUTES\" -gt 0 ] || [ \"$CATCH_ALL_ROUTES\" -gt 0 ]; then\n report_analysis \"FOUND\" \"$((DYNAMIC_ROUTES + CATCH_ALL_ROUTES)) dynamic routes detected\"\n \n if [ -f \"$ROUTES_FILE\" ]; then\n echo \" π§ Dynamic Routes:\" >&2\n grep -E \"^(dynamic|catch-all)\" \"$ROUTES_FILE\" | while IFS='|' read -r type route file; do\n echo \" β’ $route ($type)\" >&2\n done\n fi\n fi\n \n # Generate route map file\n if [ \"$TOTAL_ROUTES\" -gt 0 ] || [ \"$API_ROUTES\" -gt 0 ]; then\n echo \"π Generating route map...\" >&2\n \n ROUTE_MAP_OUTPUT=\"nextjs-routes.json\"\n \n cat > \"$ROUTE_MAP_OUTPUT\" << EOF\n{\n \"generated\": \"$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")\",\n \"project\": \"$(basename \"$(pwd)\")\",\n \"totalRoutes\": $TOTAL_ROUTES,\n \"apiRoutes\": $API_ROUTES,\n \"routes\": {\n \"static\": [\nEOF\n \n # Add static routes\n if [ -f \"$ROUTES_FILE\" ]; then\n grep \"^static\" \"$ROUTES_FILE\" | while IFS='|' read -r type route file; do\n echo \" { \\\"path\\\": \\\"$route\\\", \\\"file\\\": \\\"$file\\\" },\" >> \"$ROUTE_MAP_OUTPUT\"\n done\n # Remove trailing comma from last entry\n sed -i '$ s/,$//' \"$ROUTE_MAP_OUTPUT\" 2>/dev/null || sed -i '' '$ s/,$//' \"$ROUTE_MAP_OUTPUT\" 2>/dev/null\n fi\n \n cat >> \"$ROUTE_MAP_OUTPUT\" << EOF\n ],\n \"dynamic\": [\nEOF\n \n # Add dynamic routes\n if [ -f \"$ROUTES_FILE\" ]; then\n grep \"^dynamic\" \"$ROUTES_FILE\" | while IFS='|' read -r type route file; do\n echo \" { \\\"path\\\": \\\"$route\\\", \\\"file\\\": \\\"$file\\\", \\\"type\\\": \\\"dynamic\\\" },\" >> \"$ROUTE_MAP_OUTPUT\"\n done\n grep \"^catch-all\" \"$ROUTES_FILE\" | while IFS='|' read -r type route file; do\n echo \" { \\\"path\\\": \\\"$route\\\", \\\"file\\\": \\\"$file\\\", \\\"type\\\": \\\"catch-all\\\" },\" >> \"$ROUTE_MAP_OUTPUT\"\n done\n # Remove trailing comma from last entry\n sed -i '$ s/,$//' \"$ROUTE_MAP_OUTPUT\" 2>/dev/null || sed -i '' '$ s/,$//' \"$ROUTE_MAP_OUTPUT\" 2>/dev/null\n fi\n \n cat >> \"$ROUTE_MAP_OUTPUT\" << EOF\n ],\n \"api\": [\nEOF\n \n # Add API routes\n if [ -f \"$API_ROUTES_FILE\" ]; then\n cat \"$API_ROUTES_FILE\" | while IFS='|' read -r type route file; do\n echo \" { \\\"path\\\": \\\"$route\\\", \\\"file\\\": \\\"$file\\\" },\" >> \"$ROUTE_MAP_OUTPUT\"\n done\n # Remove trailing comma from last entry\n sed -i '$ s/,$//' \"$ROUTE_MAP_OUTPUT\" 2>/dev/null || sed -i '' '$ s/,$//' \"$ROUTE_MAP_OUTPUT\" 2>/dev/null\n fi\n \n cat >> \"$ROUTE_MAP_OUTPUT\" << EOF\n ]\n }\n}\nEOF\n \n report_analysis \"FOUND\" \"Route map generated: $ROUTE_MAP_OUTPUT\"\n fi\n \n # Performance and optimization recommendations\n echo \"π‘ Route optimization recommendations...\" >&2\n \n if [ \"$DYNAMIC_ROUTES\" -gt 10 ]; then\n echo \" β’ Consider using ISR for frequently accessed dynamic routes\" >&2\n fi\n \n if [ \"$API_ROUTES\" -gt 0 ]; then\n echo \" β’ Consider API route optimization and caching strategies\" >&2\n fi\n \n if [ \"$CATCH_ALL_ROUTES\" -gt 3 ]; then\n echo \" β’ Review catch-all routes for potential over-use\" >&2\n fi\n \n if [ \"$TOTAL_ROUTES\" -gt 100 ]; then\n echo \" β’ Large application - consider route-based code splitting\" >&2\n fi\n \n # Clean up temporary files\n rm -f \"$ROUTES_FILE\" \"$API_ROUTES_FILE\" \"$ROUTE_MAP_FILE\"\n \n echo \"\" >&2\n echo \"π Next.js Route Analysis Summary:\" >&2\n echo \"=================================\" >&2\n echo \" π File analyzed: $(basename \"$FILE_PATH\")\" >&2\n echo \" πΊοΈ Total routes found: $((TOTAL_ROUTES + API_ROUTES))\" >&2\n echo \" π Route breakdown: $STATIC_ROUTES static, $DYNAMIC_ROUTES dynamic, $API_ROUTES API\" >&2\n echo \" β οΈ Warnings: $WARNINGS\" >&2\n echo \" β Errors: $ERRORS\" >&2\n \n if [ \"$ERRORS\" -eq 0 ]; then\n if [ \"$TOTAL_ROUTES\" -gt 0 ] || [ \"$API_ROUTES\" -gt 0 ]; then\n echo \" π Status: SUCCESS - Route analysis complete\" >&2\n else\n echo \" β
Status: INFO - No routes found to analyze\" >&2\n fi\n else\n echo \" β Status: ISSUES - Route analysis completed with errors\" >&2\n fi\n \n echo \"\" >&2\n echo \"π‘ Next.js Routing Best Practices:\" >&2\n echo \" β’ Use static routes when possible for better performance\" >&2\n echo \" β’ Implement proper error boundaries for dynamic routes\" >&2\n echo \" β’ Consider ISR for dynamic content that doesn't change often\" >&2\n echo \" β’ Use API routes for server-side functionality\" >&2\n echo \" β’ Organize routes logically with proper folder structure\" >&2\n echo \" β’ Document your routing strategy for team collaboration\" >&2\n \nelse\n # Not a Next.js file, exit silently\n exit 0\nfi\n\nexit 0"
}.claude/hooks/~/.claude/hooks/{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/nextjs-route-analyzer.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 this is a Next.js page, component, or route file
if [[ "$FILE_PATH" == *pages/*.* ]] || [[ "$FILE_PATH" == *app/*.* ]] || [[ "$FILE_PATH" == *src/pages/*.* ]] || [[ "$FILE_PATH" == *src/app/*.* ]]; then
echo "πΊοΈ Next.js Route Analysis for: $(basename "$FILE_PATH")" >&2
# Initialize analysis counters
TOTAL_ROUTES=0
STATIC_ROUTES=0
DYNAMIC_ROUTES=0
API_ROUTES=0
CATCH_ALL_ROUTES=0
ERRORS=0
WARNINGS=0
# Function to report analysis results
report_analysis() {
local level="$1"
local message="$2"
case "$level" in
"ERROR")
echo "β ERROR: $message" >&2
ERRORS=$((ERRORS + 1))
;;
"WARNING")
echo "β οΈ WARNING: $message" >&2
WARNINGS=$((WARNINGS + 1))
;;
"INFO")
echo "βΉοΈ INFO: $message" >&2
;;
"FOUND")
echo "β
FOUND: $message" >&2
;;
esac
}
# Detect Next.js project structure
PROJECT_ROOT="."
PAGES_DIR=""
APP_DIR=""
SRC_PAGES_DIR=""
SRC_APP_DIR=""
# Find project root and routing directories
if [ -f "./package.json" ]; then
# Check if this is a Next.js project
if grep -q '"next"' "./package.json" 2>/dev/null; then
echo " π¦ Next.js project detected" >&2
# Check for different routing structures
[ -d "./pages" ] && PAGES_DIR="./pages"
[ -d "./app" ] && APP_DIR="./app"
[ -d "./src/pages" ] && SRC_PAGES_DIR="./src/pages"
[ -d "./src/app" ] && SRC_APP_DIR="./src/app"
if [ -n "$APP_DIR" ] || [ -n "$SRC_APP_DIR" ]; then
echo " π§ App Router structure detected" >&2
fi
if [ -n "$PAGES_DIR" ] || [ -n "$SRC_PAGES_DIR" ]; then
echo " π Pages Router structure detected" >&2
fi
else
report_analysis "WARNING" "Not a Next.js project (no Next.js dependency found)"
fi
else
report_analysis "WARNING" "No package.json found - may not be in project root"
fi
# Create temporary files for route analysis
ROUTES_FILE="/tmp/nextjs_routes_$$"
API_ROUTES_FILE="/tmp/nextjs_api_routes_$$"
ROUTE_MAP_FILE="/tmp/nextjs_route_map_$$"
echo "π Analyzing route structure..." >&2
# Function to analyze route type
analyze_route_type() {
local route_path="$1"
local file_path="$2"
# Check if it's an API route
if [[ "$file_path" == *"/api/"* ]] || [[ "$route_path" == *"/api/"* ]]; then
API_ROUTES=$((API_ROUTES + 1))
echo "api|$route_path|$file_path" >> "$API_ROUTES_FILE"
return
fi
# Check route complexity
if [[ "$route_path" == *"[..."* ]]; then
# Catch-all route
CATCH_ALL_ROUTES=$((CATCH_ALL_ROUTES + 1))
echo "catch-all|$route_path|$file_path" >> "$ROUTES_FILE"
elif [[ "$route_path" == *"["* ]]; then
# Dynamic route
DYNAMIC_ROUTES=$((DYNAMIC_ROUTES + 1))
echo "dynamic|$route_path|$file_path" >> "$ROUTES_FILE"
else
# Static route
STATIC_ROUTES=$((STATIC_ROUTES + 1))
echo "static|$route_path|$file_path" >> "$ROUTES_FILE"
fi
}
# Function to convert file path to route
file_to_route() {
local file_path="$1"
local base_dir="$2"
# Remove base directory and file extension
local route=$(echo "$file_path" | sed "s|^$base_dir||" | sed 's|\\.[jt]sx\\?$||')
# Handle special Next.js file names
route=$(echo "$route" | sed 's|/page$||') # Remove /page suffix
route=$(echo "$route" | sed 's|/route$||') # Remove /route suffix
route=$(echo "$route" | sed 's|/index$||') # Remove /index suffix
# Convert empty route to root
[ -z "$route" ] && route="/"
# Ensure route starts with /
[[ "$route" != /* ]] && route="/$route"
echo "$route"
}
# Analyze Pages Router (if exists)
for pages_dir in "$PAGES_DIR" "$SRC_PAGES_DIR"; do
if [ -n "$pages_dir" ] && [ -d "$pages_dir" ]; then
echo " π Analyzing Pages Router in $pages_dir..." >&2
# Find all page files
find "$pages_dir" -type f \( -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" \) 2>/dev/null | while read -r file; do
if [ -f "$file" ]; then
route=$(file_to_route "$file" "$pages_dir")
analyze_route_type "$route" "$file"
echo " π $route <- $file" >&2
fi
done
fi
done
# Analyze App Router (if exists)
for app_dir in "$APP_DIR" "$SRC_APP_DIR"; do
if [ -n "$app_dir" ] && [ -d "$app_dir" ]; then
echo " π§ Analyzing App Router in $app_dir..." >&2
# Find page.tsx/jsx and route.tsx/jsx files
find "$app_dir" -type f \( -name "page.js" -o -name "page.jsx" -o -name "page.ts" -o -name "page.tsx" -o -name "route.js" -o -name "route.jsx" -o -name "route.ts" -o -name "route.tsx" \) 2>/dev/null | while read -r file; do
if [ -f "$file" ]; then
route=$(file_to_route "$file" "$app_dir")
analyze_route_type "$route" "$file"
echo " π $route <- $file" >&2
fi
done
# Find layout files
find "$app_dir" -type f \( -name "layout.js" -o -name "layout.jsx" -o -name "layout.ts" -o -name "layout.tsx" \) 2>/dev/null | while read -r file; do
if [ -f "$file" ]; then
layout_path=$(echo "$file" | sed "s|^$app_dir||" | sed 's|/layout\\.[jt]sx\\?$||')
[ -z "$layout_path" ] && layout_path="/"
[[ "$layout_path" != /* ]] && layout_path="/$layout_path"
echo " π¨ Layout: $layout_path <- $file" >&2
fi
done
fi
done
# Calculate totals
TOTAL_ROUTES=$((STATIC_ROUTES + DYNAMIC_ROUTES + CATCH_ALL_ROUTES))
# Generate route analysis report
echo "" >&2
echo "π Route Analysis Results:" >&2
echo "=========================" >&2
echo " π Total Routes: $TOTAL_ROUTES" >&2
echo " π Static Routes: $STATIC_ROUTES" >&2
echo " π§ Dynamic Routes: $DYNAMIC_ROUTES" >&2
echo " π Catch-all Routes: $CATCH_ALL_ROUTES" >&2
echo " π API Routes: $API_ROUTES" >&2
# Route complexity analysis
if [ "$TOTAL_ROUTES" -eq 0 ]; then
report_analysis "WARNING" "No routes found in the project"
elif [ "$TOTAL_ROUTES" -gt 50 ]; then
report_analysis "INFO" "Large application with $TOTAL_ROUTES routes"
else
report_analysis "INFO" "Application has $TOTAL_ROUTES routes"
fi
# API route analysis
if [ "$API_ROUTES" -gt 0 ]; then
report_analysis "FOUND" "$API_ROUTES API endpoints detected"
if [ -f "$API_ROUTES_FILE" ]; then
echo " π API Endpoints:" >&2
cat "$API_ROUTES_FILE" | while IFS='|' read -r type route file; do
echo " β’ $route" >&2
done
fi
fi
# Dynamic route analysis
if [ "$DYNAMIC_ROUTES" -gt 0 ] || [ "$CATCH_ALL_ROUTES" -gt 0 ]; then
report_analysis "FOUND" "$((DYNAMIC_ROUTES + CATCH_ALL_ROUTES)) dynamic routes detected"
if [ -f "$ROUTES_FILE" ]; then
echo " π§ Dynamic Routes:" >&2
grep -E "^(dynamic|catch-all)" "$ROUTES_FILE" | while IFS='|' read -r type route file; do
echo " β’ $route ($type)" >&2
done
fi
fi
# Generate route map file
if [ "$TOTAL_ROUTES" -gt 0 ] || [ "$API_ROUTES" -gt 0 ]; then
echo "π Generating route map..." >&2
ROUTE_MAP_OUTPUT="nextjs-routes.json"
cat > "$ROUTE_MAP_OUTPUT" << EOF
{
"generated": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
"project": "$(basename "$(pwd)")",
"totalRoutes": $TOTAL_ROUTES,
"apiRoutes": $API_ROUTES,
"routes": {
"static": [
EOF
# Add static routes
if [ -f "$ROUTES_FILE" ]; then
grep "^static" "$ROUTES_FILE" | while IFS='|' read -r type route file; do
echo " { \"path\": \"$route\", \"file\": \"$file\" }," >> "$ROUTE_MAP_OUTPUT"
done
# Remove trailing comma from last entry
sed -i '$ s/,$//' "$ROUTE_MAP_OUTPUT" 2>/dev/null || sed -i '' '$ s/,$//' "$ROUTE_MAP_OUTPUT" 2>/dev/null
fi
cat >> "$ROUTE_MAP_OUTPUT" << EOF
],
"dynamic": [
EOF
# Add dynamic routes
if [ -f "$ROUTES_FILE" ]; then
grep "^dynamic" "$ROUTES_FILE" | while IFS='|' read -r type route file; do
echo " { \"path\": \"$route\", \"file\": \"$file\", \"type\": \"dynamic\" }," >> "$ROUTE_MAP_OUTPUT"
done
grep "^catch-all" "$ROUTES_FILE" | while IFS='|' read -r type route file; do
echo " { \"path\": \"$route\", \"file\": \"$file\", \"type\": \"catch-all\" }," >> "$ROUTE_MAP_OUTPUT"
done
# Remove trailing comma from last entry
sed -i '$ s/,$//' "$ROUTE_MAP_OUTPUT" 2>/dev/null || sed -i '' '$ s/,$//' "$ROUTE_MAP_OUTPUT" 2>/dev/null
fi
cat >> "$ROUTE_MAP_OUTPUT" << EOF
],
"api": [
EOF
# Add API routes
if [ -f "$API_ROUTES_FILE" ]; then
cat "$API_ROUTES_FILE" | while IFS='|' read -r type route file; do
echo " { \"path\": \"$route\", \"file\": \"$file\" }," >> "$ROUTE_MAP_OUTPUT"
done
# Remove trailing comma from last entry
sed -i '$ s/,$//' "$ROUTE_MAP_OUTPUT" 2>/dev/null || sed -i '' '$ s/,$//' "$ROUTE_MAP_OUTPUT" 2>/dev/null
fi
cat >> "$ROUTE_MAP_OUTPUT" << EOF
]
}
}
EOF
report_analysis "FOUND" "Route map generated: $ROUTE_MAP_OUTPUT"
fi
# Performance and optimization recommendations
echo "π‘ Route optimization recommendations..." >&2
if [ "$DYNAMIC_ROUTES" -gt 10 ]; then
echo " β’ Consider using ISR for frequently accessed dynamic routes" >&2
fi
if [ "$API_ROUTES" -gt 0 ]; then
echo " β’ Consider API route optimization and caching strategies" >&2
fi
if [ "$CATCH_ALL_ROUTES" -gt 3 ]; then
echo " β’ Review catch-all routes for potential over-use" >&2
fi
if [ "$TOTAL_ROUTES" -gt 100 ]; then
echo " β’ Large application - consider route-based code splitting" >&2
fi
# Clean up temporary files
rm -f "$ROUTES_FILE" "$API_ROUTES_FILE" "$ROUTE_MAP_FILE"
echo "" >&2
echo "π Next.js Route Analysis Summary:" >&2
echo "=================================" >&2
echo " π File analyzed: $(basename "$FILE_PATH")" >&2
echo " πΊοΈ Total routes found: $((TOTAL_ROUTES + API_ROUTES))" >&2
echo " π Route breakdown: $STATIC_ROUTES static, $DYNAMIC_ROUTES dynamic, $API_ROUTES API" >&2
echo " β οΈ Warnings: $WARNINGS" >&2
echo " β Errors: $ERRORS" >&2
if [ "$ERRORS" -eq 0 ]; then
if [ "$TOTAL_ROUTES" -gt 0 ] || [ "$API_ROUTES" -gt 0 ]; then
echo " π Status: SUCCESS - Route analysis complete" >&2
else
echo " β
Status: INFO - No routes found to analyze" >&2
fi
else
echo " β Status: ISSUES - Route analysis completed with errors" >&2
fi
echo "" >&2
echo "π‘ Next.js Routing Best Practices:" >&2
echo " β’ Use static routes when possible for better performance" >&2
echo " β’ Implement proper error boundaries for dynamic routes" >&2
echo " β’ Consider ISR for dynamic content that doesn't change often" >&2
echo " β’ Use API routes for server-side functionality" >&2
echo " β’ Organize routes logically with proper folder structure" >&2
echo " β’ Document your routing strategy for team collaboration" >&2
else
# Not a Next.js file, exit silently
exit 0
fi
exit 0Hook reports no Next.js project despite valid setup
Verify package.json contains 'next' dependency and run from project root. The hook checks both /pages and /app directories, and /src variants. Ensure at least one routing directory exists.
Route map JSON has trailing commas or invalid format
The sed command to remove trailing commas may fail on macOS. Update to use 'sed -i "" ' syntax for BSD sed, or install GNU sed with 'brew install gnu-sed'. Validate output with jq.
API routes not detected in App Router structure
Ensure API routes use route.js/ts naming convention in App Router. The hook scans for /api/ path segments and route.* files. Pages Router uses pages/api/ directory structure.
Dynamic routes show incorrect parameter extraction
The hook identifies brackets in paths but doesn't parse parameter names. Use the generated nextjs-routes.json for accurate mapping. Review file paths in the 'file' property for exact parameter structure.
Hook runs on every file change causing performance issues
The hook processes all files in pages/ or app/ directories. For large projects, consider adding file type filtering (*.tsx, *.jsx only) or exclude non-route files like components and utilities.
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