blob: 7520ac6f560fd879a7cd52090dbc99fc5e5f68d8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
#!/bin/bash
# TailwindCSS Pre-push Hook
# Final checks before pushing code to ensure production-ready TailwindCSS usage
set -e
echo "🎨 Running TailwindCSS pre-push validation..."
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
# Production build test
test_production_build() {
print_status $BLUE "Testing production build..."
# Check if build script exists
if npm run --silent 2>/dev/null | grep -q "build"; then
print_status $BLUE "Running production build test..."
# Create a backup of current built files
if [[ -d "dist" ]]; then
mv dist dist.backup
fi
if [[ -d "build" ]]; then
mv build build.backup
fi
if [[ -d ".next" ]]; then
mv .next .next.backup
fi
# Run build
if npm run build >/dev/null 2>&1; then
print_status $GREEN "✅ Production build successful"
# Analyze build output
analyze_build_output
else
print_status $RED "❌ Production build failed"
# Restore backups
restore_backups
exit 1
fi
# Restore backups
restore_backups
else
print_status $YELLOW "⚠️ No build script found. Skipping production build test"
fi
}
# Restore backup directories
restore_backups() {
[[ -d "dist.backup" ]] && rm -rf dist && mv dist.backup dist
[[ -d "build.backup" ]] && rm -rf build && mv build.backup build
[[ -d ".next.backup" ]] && rm -rf .next && mv .next.backup .next
}
# Analyze build output for CSS optimization
analyze_build_output() {
print_status $BLUE "Analyzing CSS build output..."
# Find CSS files in build output
local css_files=$(find dist build .next 2>/dev/null -name "*.css" -type f | head -5)
if [[ -n "$css_files" ]]; then
local total_size=0
local file_count=0
while IFS= read -r file; do
if [[ -f "$file" ]]; then
local size=$(wc -c < "$file")
local size_kb=$((size / 1024))
total_size=$((total_size + size))
file_count=$((file_count + 1))
print_status $BLUE "📄 $(basename "$file"): ${size_kb}KB"
# Warn about large CSS files
if [[ $size_kb -gt 200 ]]; then
print_status $YELLOW "⚠️ Large CSS file detected (${size_kb}KB)"
print_status $YELLOW " Consider optimizing TailwindCSS configuration"
fi
fi
done <<< "$css_files"
local total_kb=$((total_size / 1024))
print_status $GREEN "📊 Total CSS size: ${total_kb}KB across ${file_count} files"
# Overall size warning
if [[ $total_kb -gt 500 ]]; then
print_status $RED "❌ CSS bundle too large (${total_kb}KB > 500KB)"
print_status $RED " Optimize before pushing to production"
exit 1
elif [[ $total_kb -gt 300 ]]; then
print_status $YELLOW "⚠️ CSS bundle size is high (${total_kb}KB)"
print_status $YELLOW " Consider optimization for better performance"
fi
else
print_status $YELLOW "⚠️ No CSS files found in build output"
fi
}
# Validate CSS purging effectiveness
validate_purging() {
print_status $BLUE "Validating CSS purging effectiveness..."
# Build CSS for analysis
if command -v npx >/dev/null 2>&1 && [[ -f "tailwind.config.js" ]]; then
# Create temporary input file
echo "@tailwind base; @tailwind components; @tailwind utilities;" > temp-input.css
# Generate full CSS (no purging)
if npx tailwindcss -i temp-input.css -o temp-full.css >/dev/null 2>&1; then
local full_size=$(wc -c < temp-full.css)
# Generate purged CSS (with content)
if npx tailwindcss -i temp-input.css -o temp-purged.css --minify >/dev/null 2>&1; then
local purged_size=$(wc -c < temp-purged.css)
local reduction_percent=$(( (full_size - purged_size) * 100 / full_size ))
print_status $GREEN "✅ CSS purging reduces bundle by ${reduction_percent}%"
print_status $BLUE " Full: $((full_size / 1024))KB → Purged: $((purged_size / 1024))KB"
# Warn about ineffective purging
if [[ $reduction_percent -lt 70 ]]; then
print_status $YELLOW "⚠️ Low purging effectiveness (${reduction_percent}%)"
print_status $YELLOW " Check content paths in tailwind.config.js"
fi
fi
fi
# Cleanup temporary files
rm -f temp-input.css temp-full.css temp-purged.css
fi
}
# Security and best practices validation
validate_security() {
print_status $BLUE "Validating security and best practices..."
# Check for hardcoded values that might contain sensitive data
local suspicious_patterns=$(grep -r "class[Name]*=.*\(password\|token\|key\|secret\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | head -3 || true)
if [[ -n "$suspicious_patterns" ]]; then
print_status $YELLOW "⚠️ Suspicious patterns in class names:"
echo "$suspicious_patterns"
fi
# Check for XSS-prone dynamic class generation
local dynamic_classes=$(grep -r "class[Name]*=.*\${.*}" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l)
if [[ $dynamic_classes -gt 20 ]]; then
print_status $YELLOW "⚠️ High usage of dynamic class generation (${dynamic_classes} instances)"
print_status $YELLOW " Ensure proper sanitization of user input"
fi
print_status $GREEN "✅ Security validation completed"
}
# Performance impact analysis
analyze_performance_impact() {
print_status $BLUE "Analyzing performance impact..."
# Check for performance-impacting patterns
local heavy_animations=$(grep -r "animate-\(bounce\|ping\|pulse\|spin\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l)
if [[ $heavy_animations -gt 20 ]]; then
print_status $YELLOW "⚠️ High usage of animations (${heavy_animations} instances)"
print_status $YELLOW " Consider performance impact on low-end devices"
fi
# Check for layout-shifting utilities
local layout_shifts=$(grep -r "transition-\(width\|height\|padding\|margin\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l)
if [[ $layout_shifts -gt 10 ]]; then
print_status $YELLOW "⚠️ Layout-shifting transitions detected (${layout_shifts} instances)"
print_status $YELLOW " May cause poor Cumulative Layout Shift (CLS) scores"
fi
# Check for excessive gradient usage
local gradients=$(grep -r "gradient-to-\|from-\|via-\|to-" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l)
if [[ $gradients -gt 50 ]]; then
print_status $YELLOW "⚠️ Heavy gradient usage (${gradients} instances)"
print_status $YELLOW " Consider performance impact and CSS bundle size"
fi
print_status $GREEN "✅ Performance analysis completed"
}
# Browser compatibility check
check_browser_compatibility() {
print_status $BLUE "Checking browser compatibility..."
local config_file="tailwind.config.js"
if [[ -f "tailwind.config.ts" ]]; then
config_file="tailwind.config.ts"
fi
# Check for modern CSS features that might need fallbacks
local modern_features=$(grep -r "\(backdrop-\|container\|aspect-\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l)
if [[ $modern_features -gt 0 ]]; then
print_status $YELLOW "⚠️ Modern CSS features detected (${modern_features} instances)"
print_status $YELLOW " Verify browser support requirements"
# Check for autoprefixer
if npm list autoprefixer >/dev/null 2>&1; then
print_status $GREEN "✅ Autoprefixer installed for vendor prefixes"
else
print_status $YELLOW "⚠️ Consider installing autoprefixer for better browser support"
fi
fi
print_status $GREEN "✅ Browser compatibility check completed"
}
# Final accessibility audit
final_accessibility_audit() {
print_status $BLUE "Running final accessibility audit..."
# Check for proper focus management
local focus_traps=$(grep -r "focus-trap\|focus-within\|focus-visible" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l)
if [[ $focus_traps -eq 0 ]]; then
print_status $YELLOW "⚠️ No focus management utilities detected"
print_status $YELLOW " Ensure proper keyboard navigation support"
else
print_status $GREEN "✅ Focus management utilities found"
fi
# Check for color contrast considerations
local contrast_utilities=$(grep -r "contrast-\|brightness-" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l)
if [[ $contrast_utilities -gt 0 ]]; then
print_status $GREEN "✅ Color contrast utilities in use"
fi
# Check for screen reader utilities
local sr_utilities=$(grep -r "sr-only\|not-sr-only" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l)
if [[ $sr_utilities -eq 0 ]]; then
print_status $YELLOW "⚠️ No screen reader utilities detected"
print_status $YELLOW " Consider accessibility for screen reader users"
else
print_status $GREEN "✅ Screen reader utilities found"
fi
print_status $GREEN "✅ Accessibility audit completed"
}
# Generate pre-push report
generate_push_report() {
print_status $BLUE "Generating pre-push report..."
local report_file=".tailwindcss-push-report.txt"
local timestamp=$(date)
cat > "$report_file" << EOF
TailwindCSS Pre-Push Report
===========================
Generated: $timestamp
Branch: $(git branch --show-current 2>/dev/null || echo "unknown")
Commit: $(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
Build Status:
$(npm run build >/dev/null 2>&1 && echo "✅ Build successful" || echo "❌ Build failed")
CSS Bundle Analysis:
$(find dist build .next 2>/dev/null -name "*.css" -type f | while read file; do
if [[ -f "$file" ]]; then
echo "- $(basename "$file"): $(($(wc -c < "$file") / 1024))KB"
fi
done | head -5 || echo "- No CSS files found")
Code Quality Checks:
- Long class strings: $(grep -r "class[Name]*=['\"][^'\"]*['\"]" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | awk 'length($0) > 150' | wc -l | tr -d ' ')
- Dynamic classes: $(grep -r "class[Name]*=.*\${.*}" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ')
- Arbitrary values: $(grep -r "\[\w*\]" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ')
Performance Metrics:
- Animation utilities: $(grep -r "animate-" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ')
- Layout transitions: $(grep -r "transition-\(width\|height\|padding\|margin\)" src/ 2>/dev/null | wc -l | tr -d ' ')
- Gradient usage: $(grep -r "gradient-to-\|from-\|via-\|to-" src/ 2>/dev/null | wc -l | tr -d ' ')
Accessibility Features:
- Focus utilities: $(grep -r "focus-" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ')
- Screen reader utilities: $(grep -r "sr-only\|not-sr-only" src/ 2>/dev/null | wc -l | tr -d ' ')
Recommendations:
$(if grep -r "class[Name]*=['\"][^'\"]*['\"]" src/ 2>/dev/null | sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | awk 'length($0) > 150' | head -1 >/dev/null 2>&1; then echo "- Consider component extraction for long utility combinations"; fi)
$(if [[ $(grep -r "\[\w*\]" src/ 2>/dev/null | wc -l) -gt 10 ]]; then echo "- Consider adding custom utilities to config instead of arbitrary values"; fi)
$(if [[ $(grep -r "animate-" src/ 2>/dev/null | wc -l) -gt 20 ]]; then echo "- Review animation usage for performance impact"; fi)
Status: $(if npm run build >/dev/null 2>&1; then echo "✅ Ready for production"; else echo "❌ Issues detected - review before pushing"; fi)
EOF
print_status $GREEN "✅ Pre-push report saved to $report_file"
# Show critical issues in console
if ! npm run build >/dev/null 2>&1; then
print_status $RED "❌ Build failures detected - see report for details"
return 1
fi
return 0
}
# Main execution
main() {
local start_time=$(date +%s)
print_status $BLUE "🎨 TailwindCSS Pre-Push Validation"
print_status $BLUE "===================================="
# Run all validation tasks
test_production_build
validate_purging
validate_security
analyze_performance_impact
check_browser_compatibility
final_accessibility_audit
# Generate final report
if generate_push_report; then
local end_time=$(date +%s)
local duration=$((end_time - start_time))
print_status $GREEN "✅ All pre-push validations completed in ${duration}s"
print_status $BLUE "🚀 Code is ready for production push!"
print_status $YELLOW "📄 See .tailwindcss-push-report.txt for detailed analysis"
else
print_status $RED "❌ Pre-push validation failed"
print_status $RED "Fix issues before pushing to production"
exit 1
fi
}
# Run the main function
main
|