cssminify2 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +10 -5
- data/CHANGELOG.md +121 -0
- data/Dockerfile +16 -0
- data/Gemfile +1 -1
- data/README.md +501 -42
- data/cssminify2.gemspec +6 -2
- data/docs/ADVANCED_USAGE.md +616 -0
- data/docs/API_REFERENCE.md +464 -0
- data/docs/EXAMPLES.md +844 -0
- data/docs/MIGRATION_GUIDE.md +586 -0
- data/lib/cssminify2/cssmin.rb +89 -7
- data/lib/cssminify2/cssmin_enhanced.rb +424 -0
- data/lib/cssminify2/enhanced.rb +818 -0
- data/lib/cssminify2/version.rb +1 -1
- data/lib/cssminify2.rb +53 -4
- data/spec/cssminify_spec.rb +49 -34
- data/spec/tests/README +6 -0
- data/spec/tests/_munge.js +8 -0
- data/spec/tests/_munge.js.min +1 -0
- data/spec/tests/_string_combo.js +5 -0
- data/spec/tests/_string_combo.js.min +1 -0
- data/spec/tests/_string_combo2.js +4 -0
- data/spec/tests/_string_combo2.js.min +1 -0
- data/spec/tests/_string_combo3.js +5 -0
- data/spec/tests/_string_combo3.js.min +1 -0
- data/spec/tests/_syntax_error.js +73 -0
- data/spec/tests/_syntax_error.js.min +1 -0
- data/spec/tests/border-none.css +6 -1
- data/spec/tests/border-none.css.min +1 -1
- data/spec/tests/bug-flex.css +3 -0
- data/spec/tests/bug-flex.css.min +1 -0
- data/spec/tests/bug-nested-pseudoclass.css +3 -0
- data/spec/tests/bug-nested-pseudoclass.css.min +1 -0
- data/spec/tests/bug-preservetoken-calc.css +8 -0
- data/spec/tests/bug-preservetoken-calc.css.min +1 -0
- data/spec/tests/color-keyword.css +1 -0
- data/spec/tests/color-keyword.css.min +1 -0
- data/spec/tests/color.css +2 -0
- data/spec/tests/color.css.min +1 -1
- data/spec/tests/concat-charset.css +2 -2
- data/spec/tests/concat-charset.css.min +1 -1
- data/spec/tests/dataurl-singlequote-font.css +1 -1
- data/spec/tests/dataurl-validity.html +29 -0
- data/spec/tests/float.js +2 -0
- data/spec/tests/float.js.min +1 -0
- data/spec/tests/hsla-issue81.css.FAIL +4 -0
- data/spec/tests/hsla-issue81.css.min +1 -0
- data/spec/tests/ie-backslash9-hack.css +2 -0
- data/spec/tests/ie-backslash9-hack.css.min +1 -0
- data/spec/tests/issue-59.css +7 -0
- data/spec/tests/issue-59.css.min +1 -0
- data/spec/tests/issue151.css +8 -0
- data/spec/tests/issue151.css.min +1 -0
- data/spec/tests/issue172.css.FAIL +4 -0
- data/spec/tests/issue172.css.min +1 -0
- data/spec/tests/issue180.css +16 -0
- data/spec/tests/issue180.css.min +1 -0
- data/spec/tests/issue205.css +2 -0
- data/spec/tests/issue205.css.min +1 -0
- data/spec/tests/issue221.css +1 -1
- data/spec/tests/issue221.css.min +1 -1
- data/spec/tests/issue222.css +2 -2
- data/spec/tests/issue222.css.min +1 -1
- data/spec/tests/issue71.js.FAIL +4 -0
- data/spec/tests/issue71.js.min +1 -0
- data/spec/tests/issue86.js +2 -0
- data/spec/tests/issue86.js.min +1 -0
- data/spec/tests/jquery-1.6.4.js +9046 -0
- data/spec/tests/jquery-1.6.4.js.min +23 -0
- data/spec/tests/lowercasing.css +63 -0
- data/spec/tests/lowercasing.css.min +1 -0
- data/spec/tests/media-test.css +2 -2
- data/spec/tests/old-ie-filter-matrix.css +8 -0
- data/spec/tests/old-ie-filter-matrix.css.min +1 -0
- data/spec/tests/opera-pixel-ratio.css +14 -0
- data/spec/tests/opera-pixel-ratio.css.min +1 -0
- data/spec/tests/pointzeros.css +6 -0
- data/spec/tests/pointzeros.css.min +1 -0
- data/spec/tests/preserve-important.css +1 -0
- data/spec/tests/preserve-important.css.min +1 -0
- data/spec/tests/promise-catch-finally-issue203.js +4 -0
- data/spec/tests/promise-catch-finally-issue203.js.min +1 -0
- data/spec/tests/pseudo-first.css +2 -2
- data/spec/tests/rgb-issue81.css.FAIL +4 -0
- data/spec/tests/rgb-issue81.css.min +1 -0
- data/spec/tests/suite.rhino +3 -0
- data/spec/tests/suite.sh +49 -0
- data/spec/tests/zeros.css +2 -2
- data/spec/tests/zeros.css.min +1 -1
- metadata +129 -14
- data/spec/tests/bug2528093.css +0 -3
- data/spec/tests/bug2528093.css.min +0 -1
- data/spec/tests/keyframe.css +0 -4
- data/spec/tests/keyframe.css.min +0 -1
@@ -0,0 +1,586 @@
|
|
1
|
+
# Migration Guide
|
2
|
+
|
3
|
+
Complete guide for migrating to CSSminify2 v2.x and adopting enhanced features.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [From v1.x to v2.x](#from-v1x-to-v2x)
|
8
|
+
- [Adopting Enhanced Features](#adopting-enhanced-features)
|
9
|
+
- [Framework Integration Updates](#framework-integration-updates)
|
10
|
+
- [Build Tool Integration](#build-tool-integration)
|
11
|
+
- [Troubleshooting Migration Issues](#troubleshooting-migration-issues)
|
12
|
+
|
13
|
+
## From v1.x to v2.x
|
14
|
+
|
15
|
+
### Zero Breaking Changes
|
16
|
+
|
17
|
+
**Good news!** CSSminify2 v2.x is 100% backward compatible with v1.x. Your existing code will continue to work exactly as before.
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# This code works identically in v1.x and v2.x
|
21
|
+
CSSminify2.compress(css_string)
|
22
|
+
CSSminify2.compress(css_string, 200) # With line length
|
23
|
+
|
24
|
+
compressor = CSSminify2.new
|
25
|
+
compressor.compress(css_string)
|
26
|
+
```
|
27
|
+
|
28
|
+
### What's New in v2.x
|
29
|
+
|
30
|
+
- **Enhanced compression engine** - Up to 63% compression ratios
|
31
|
+
- **Modern CSS support** - Grid, Flexbox, Custom Properties
|
32
|
+
- **Configurable optimizations** - Enable only what you need
|
33
|
+
- **Detailed statistics** - Performance insights and metrics
|
34
|
+
- **Robust error handling** - Production-ready reliability
|
35
|
+
- **Comprehensive test suite** - 95.8% YUI compatibility
|
36
|
+
|
37
|
+
### Dependency Updates
|
38
|
+
|
39
|
+
If you're upgrading from v1.x, you may need to update your dependencies:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# Gemfile - Old
|
43
|
+
gem 'rspec', '~> 2.7'
|
44
|
+
source 'http://rubygems.org'
|
45
|
+
|
46
|
+
# Gemfile - New (v2.x)
|
47
|
+
gem 'rspec', '~> 3.12' # Updated for modern Ruby compatibility
|
48
|
+
source 'https://rubygems.org' # HTTPS for security
|
49
|
+
```
|
50
|
+
|
51
|
+
## Adopting Enhanced Features
|
52
|
+
|
53
|
+
### Phase 1: Safe Optimizations
|
54
|
+
|
55
|
+
Start with the safest optimizations that provide good benefits with minimal risk:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# Replace this
|
59
|
+
result = CSSminify2.compress(css)
|
60
|
+
|
61
|
+
# With this
|
62
|
+
result = CSSminify2.compress_enhanced(css, {
|
63
|
+
optimize_shorthand_properties: true
|
64
|
+
})
|
65
|
+
```
|
66
|
+
|
67
|
+
**Benefits:**
|
68
|
+
- Optimizes `margin: 10px 10px 10px 10px` → `margin: 10px`
|
69
|
+
- Converts `padding: 0.0px 0rem 0vh` → `padding: 0`
|
70
|
+
- Zero risk of breaking existing CSS functionality
|
71
|
+
|
72
|
+
### Phase 2: Selector Optimization
|
73
|
+
|
74
|
+
Add selector merging for additional compression:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
result = CSSminify2.compress_enhanced(css, {
|
78
|
+
optimize_shorthand_properties: true,
|
79
|
+
merge_duplicate_selectors: true # New feature
|
80
|
+
})
|
81
|
+
```
|
82
|
+
|
83
|
+
**Benefits:**
|
84
|
+
- Merges `.btn { color: red; } .btn { background: blue; }` → `.btn { color: red; background: blue; }`
|
85
|
+
- Handles cascade order correctly
|
86
|
+
- Works with media queries and keyframes
|
87
|
+
|
88
|
+
**Testing Recommendation:**
|
89
|
+
```ruby
|
90
|
+
# Compare before and after
|
91
|
+
original_result = CSSminify2.compress(css)
|
92
|
+
enhanced_result = CSSminify2.compress_enhanced(css, {
|
93
|
+
optimize_shorthand_properties: true,
|
94
|
+
merge_duplicate_selectors: true
|
95
|
+
})
|
96
|
+
|
97
|
+
puts "Original: #{original_result.length} chars"
|
98
|
+
puts "Enhanced: #{enhanced_result.length} chars"
|
99
|
+
puts "Improvement: #{((original_result.length - enhanced_result.length).to_f / original_result.length * 100).round(2)}%"
|
100
|
+
```
|
101
|
+
|
102
|
+
### Phase 3: Full Optimization
|
103
|
+
|
104
|
+
Enable all optimizations for maximum compression:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
result = CSSminify2.compress_enhanced(css, {
|
108
|
+
merge_duplicate_selectors: true,
|
109
|
+
optimize_shorthand_properties: true,
|
110
|
+
compress_css_variables: true, # New feature
|
111
|
+
advanced_color_optimization: true # New feature
|
112
|
+
})
|
113
|
+
```
|
114
|
+
|
115
|
+
**Additional Benefits:**
|
116
|
+
- Optimizes CSS custom properties (variables)
|
117
|
+
- Enhanced color optimization with IE filter protection
|
118
|
+
- Modern CSS layout optimizations (Grid, Flexbox)
|
119
|
+
|
120
|
+
### Phase 4: Statistics and Monitoring
|
121
|
+
|
122
|
+
Add compression monitoring to your build process:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
stats = CSSminify2.compress_with_stats(css, {
|
126
|
+
merge_duplicate_selectors: true,
|
127
|
+
optimize_shorthand_properties: true,
|
128
|
+
compress_css_variables: true,
|
129
|
+
advanced_color_optimization: true
|
130
|
+
})
|
131
|
+
|
132
|
+
# Log compression metrics
|
133
|
+
Rails.logger.info "CSS compressed: #{stats[:statistics][:compression_ratio].round(2)}% reduction"
|
134
|
+
Rails.logger.warn "CSS compression used fallback" if stats[:statistics][:fallback_used]
|
135
|
+
|
136
|
+
# Use the compressed CSS
|
137
|
+
result = stats[:compressed_css]
|
138
|
+
```
|
139
|
+
|
140
|
+
## Framework Integration Updates
|
141
|
+
|
142
|
+
### Rails Asset Pipeline
|
143
|
+
|
144
|
+
#### Current Integration (v1.x style)
|
145
|
+
```ruby
|
146
|
+
# config/application.rb - Old way (still works)
|
147
|
+
config.assets.css_compressor = CSSminify2.new
|
148
|
+
```
|
149
|
+
|
150
|
+
#### Enhanced Integration (v2.x)
|
151
|
+
```ruby
|
152
|
+
# config/initializers/css_compression.rb
|
153
|
+
class EnhancedCSSCompressor
|
154
|
+
def initialize
|
155
|
+
@config = case Rails.env
|
156
|
+
when 'development'
|
157
|
+
{
|
158
|
+
optimize_shorthand_properties: true,
|
159
|
+
strict_error_handling: true # Catch issues early
|
160
|
+
}
|
161
|
+
when 'test'
|
162
|
+
{
|
163
|
+
merge_duplicate_selectors: true,
|
164
|
+
optimize_shorthand_properties: true,
|
165
|
+
strict_error_handling: true
|
166
|
+
}
|
167
|
+
when 'production'
|
168
|
+
{
|
169
|
+
merge_duplicate_selectors: true,
|
170
|
+
optimize_shorthand_properties: true,
|
171
|
+
compress_css_variables: true,
|
172
|
+
advanced_color_optimization: true,
|
173
|
+
strict_error_handling: false # Graceful fallbacks
|
174
|
+
}
|
175
|
+
else
|
176
|
+
{} # Conservative defaults
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def compress(css)
|
181
|
+
CSSminify2.compress_enhanced(css, @config)
|
182
|
+
rescue => e
|
183
|
+
Rails.logger.warn "Enhanced CSS compression failed: #{e.message}"
|
184
|
+
# Fallback to basic compression
|
185
|
+
CSSminify2.compress(css)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# config/application.rb
|
190
|
+
config.assets.css_compressor = EnhancedCSSCompressor.new
|
191
|
+
```
|
192
|
+
|
193
|
+
### Sprockets Integration
|
194
|
+
|
195
|
+
#### Basic Update
|
196
|
+
```ruby
|
197
|
+
# Old
|
198
|
+
require 'cssminify2'
|
199
|
+
Sprockets.register_compressor 'text/css', :cssminify2, CSSminify2
|
200
|
+
|
201
|
+
# New - Enhanced
|
202
|
+
require 'cssminify2'
|
203
|
+
|
204
|
+
class SprocketsEnhancedCompressor
|
205
|
+
def compress(css)
|
206
|
+
CSSminify2.compress_enhanced(css, {
|
207
|
+
merge_duplicate_selectors: true,
|
208
|
+
optimize_shorthand_properties: true
|
209
|
+
})
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
Sprockets.register_compressor 'text/css', :cssminify2_enhanced, SprocketsEnhancedCompressor
|
214
|
+
```
|
215
|
+
|
216
|
+
### Jekyll Integration
|
217
|
+
|
218
|
+
#### Create Jekyll Plugin
|
219
|
+
```ruby
|
220
|
+
# _plugins/enhanced_css_minifier.rb
|
221
|
+
module Jekyll
|
222
|
+
class EnhancedCSSMinifier < Jekyll::Generator
|
223
|
+
safe true
|
224
|
+
priority :low
|
225
|
+
|
226
|
+
def generate(site)
|
227
|
+
# Read configuration from _config.yml
|
228
|
+
config = site.config['cssminify'] || {}
|
229
|
+
|
230
|
+
options = {
|
231
|
+
merge_duplicate_selectors: config['merge_selectors'] || false,
|
232
|
+
optimize_shorthand_properties: config['optimize_shorthand'] || true,
|
233
|
+
compress_css_variables: config['compress_variables'] || false,
|
234
|
+
advanced_color_optimization: config['advanced_colors'] || false
|
235
|
+
}
|
236
|
+
|
237
|
+
site.static_files.each do |file|
|
238
|
+
next unless file.extname == '.css'
|
239
|
+
|
240
|
+
original_css = File.read(file.path)
|
241
|
+
|
242
|
+
begin
|
243
|
+
stats = CSSminify2.compress_with_stats(original_css, options)
|
244
|
+
File.write(file.path, stats[:compressed_css])
|
245
|
+
|
246
|
+
Jekyll.logger.info "CSSminify2:", "#{file.relative_path} - #{stats[:statistics][:compression_ratio].round(2)}% compression"
|
247
|
+
rescue => e
|
248
|
+
Jekyll.logger.warn "CSSminify2:", "Failed to compress #{file.relative_path}: #{e.message}"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
```
|
255
|
+
|
256
|
+
#### Jekyll Configuration
|
257
|
+
```yaml
|
258
|
+
# _config.yml
|
259
|
+
cssminify:
|
260
|
+
merge_selectors: true
|
261
|
+
optimize_shorthand: true
|
262
|
+
compress_variables: false # Conservative for theme compatibility
|
263
|
+
advanced_colors: true
|
264
|
+
```
|
265
|
+
|
266
|
+
## Build Tool Integration
|
267
|
+
|
268
|
+
### Gulp Integration
|
269
|
+
|
270
|
+
#### Create Ruby Bridge Script
|
271
|
+
```ruby
|
272
|
+
#!/usr/bin/env ruby
|
273
|
+
# tools/css_compressor.rb
|
274
|
+
require 'cssminify2'
|
275
|
+
require 'json'
|
276
|
+
|
277
|
+
# Read from STDIN, write to STDOUT for Gulp integration
|
278
|
+
input_css = STDIN.read
|
279
|
+
options_json = ARGV[0] || '{}'
|
280
|
+
|
281
|
+
begin
|
282
|
+
options = JSON.parse(options_json, symbolize_names: true)
|
283
|
+
|
284
|
+
stats = CSSminify2.compress_with_stats(input_css, options)
|
285
|
+
|
286
|
+
result = {
|
287
|
+
css: stats[:compressed_css],
|
288
|
+
originalSize: stats[:statistics][:original_size],
|
289
|
+
compressedSize: stats[:statistics][:compressed_size],
|
290
|
+
compressionRatio: stats[:statistics][:compression_ratio],
|
291
|
+
selectorsmerged: stats[:statistics][:selectors_merged] || 0,
|
292
|
+
success: true
|
293
|
+
}
|
294
|
+
|
295
|
+
puts JSON.generate(result)
|
296
|
+
rescue => e
|
297
|
+
error_result = {
|
298
|
+
css: input_css, # Return original on error
|
299
|
+
error: e.message,
|
300
|
+
success: false
|
301
|
+
}
|
302
|
+
|
303
|
+
STDERR.puts JSON.generate(error_result)
|
304
|
+
exit 1
|
305
|
+
end
|
306
|
+
```
|
307
|
+
|
308
|
+
#### Gulp Task
|
309
|
+
```javascript
|
310
|
+
const { src, dest } = require('gulp');
|
311
|
+
const { spawn } = require('child_process');
|
312
|
+
const through = require('through2');
|
313
|
+
|
314
|
+
function cssminify(options = {}) {
|
315
|
+
return through.obj(function(file, enc, cb) {
|
316
|
+
if (file.isNull()) {
|
317
|
+
cb(null, file);
|
318
|
+
return;
|
319
|
+
}
|
320
|
+
|
321
|
+
const ruby = spawn('ruby', ['tools/css_compressor.rb', JSON.stringify(options)]);
|
322
|
+
let result = '';
|
323
|
+
let error = '';
|
324
|
+
|
325
|
+
ruby.stdout.on('data', (data) => result += data);
|
326
|
+
ruby.stderr.on('data', (data) => error += data);
|
327
|
+
|
328
|
+
ruby.on('close', (code) => {
|
329
|
+
if (code !== 0) {
|
330
|
+
cb(new Error(`CSS compression failed: ${error}`));
|
331
|
+
return;
|
332
|
+
}
|
333
|
+
|
334
|
+
try {
|
335
|
+
const compression_result = JSON.parse(result);
|
336
|
+
file.contents = Buffer.from(compression_result.css);
|
337
|
+
|
338
|
+
console.log(`CSS compressed: ${compression_result.compressionRatio.toFixed(2)}% reduction`);
|
339
|
+
cb(null, file);
|
340
|
+
} catch (parseError) {
|
341
|
+
cb(parseError);
|
342
|
+
}
|
343
|
+
});
|
344
|
+
|
345
|
+
ruby.stdin.write(file.contents);
|
346
|
+
ruby.stdin.end();
|
347
|
+
});
|
348
|
+
}
|
349
|
+
|
350
|
+
// Usage
|
351
|
+
function compressCSS() {
|
352
|
+
return src('src/**/*.css')
|
353
|
+
.pipe(cssminify({
|
354
|
+
merge_duplicate_selectors: true,
|
355
|
+
optimize_shorthand_properties: true,
|
356
|
+
compress_css_variables: true
|
357
|
+
}))
|
358
|
+
.pipe(dest('dist/'));
|
359
|
+
}
|
360
|
+
|
361
|
+
exports.css = compressCSS;
|
362
|
+
```
|
363
|
+
|
364
|
+
### Webpack Integration
|
365
|
+
|
366
|
+
#### Create Webpack Plugin
|
367
|
+
```ruby
|
368
|
+
# lib/webpack_css_plugin.rb
|
369
|
+
class WebpackCSSPlugin
|
370
|
+
def self.compress(css_content, options_json = '{}')
|
371
|
+
require 'cssminify2'
|
372
|
+
require 'json'
|
373
|
+
|
374
|
+
options = JSON.parse(options_json, symbolize_names: true)
|
375
|
+
|
376
|
+
stats = CSSminify2.compress_with_stats(css_content, options)
|
377
|
+
|
378
|
+
{
|
379
|
+
css: stats[:compressed_css],
|
380
|
+
stats: {
|
381
|
+
originalSize: stats[:statistics][:original_size],
|
382
|
+
compressedSize: stats[:statistics][:compressed_size],
|
383
|
+
compressionRatio: stats[:statistics][:compression_ratio],
|
384
|
+
selectorsmerged: stats[:statistics][:selectors_merged] || 0
|
385
|
+
}
|
386
|
+
}.to_json
|
387
|
+
rescue => e
|
388
|
+
{
|
389
|
+
css: css_content,
|
390
|
+
error: e.message,
|
391
|
+
stats: { fallbackUsed: true }
|
392
|
+
}.to_json
|
393
|
+
end
|
394
|
+
end
|
395
|
+
```
|
396
|
+
|
397
|
+
## Troubleshooting Migration Issues
|
398
|
+
|
399
|
+
### Common Issues and Solutions
|
400
|
+
|
401
|
+
#### Issue: "Enhanced features not working"
|
402
|
+
```ruby
|
403
|
+
# Problem: Using old API
|
404
|
+
result = CSSminify2.compress(css, { merge_duplicate_selectors: true }) # ❌ Won't work
|
405
|
+
|
406
|
+
# Solution: Use enhanced API
|
407
|
+
result = CSSminify2.compress_enhanced(css, { merge_duplicate_selectors: true }) # ✅ Correct
|
408
|
+
```
|
409
|
+
|
410
|
+
#### Issue: "CSS breaks after compression"
|
411
|
+
```ruby
|
412
|
+
# Problem: Aggressive settings breaking CSS
|
413
|
+
result = CSSminify2.compress_enhanced(css, {
|
414
|
+
merge_duplicate_selectors: true,
|
415
|
+
strict_error_handling: false # Hiding errors
|
416
|
+
})
|
417
|
+
|
418
|
+
# Solution: Enable strict mode to catch issues
|
419
|
+
begin
|
420
|
+
result = CSSminify2.compress_enhanced(css, {
|
421
|
+
merge_duplicate_selectors: true,
|
422
|
+
strict_error_handling: true # Will throw detailed errors
|
423
|
+
})
|
424
|
+
rescue CSSminify2Enhanced::MalformedCSSError => e
|
425
|
+
puts "CSS validation failed:"
|
426
|
+
e.css_errors.each { |error| puts "- #{error}" }
|
427
|
+
# Fix CSS issues or use conservative settings
|
428
|
+
end
|
429
|
+
```
|
430
|
+
|
431
|
+
#### Issue: "Unexpected compression results"
|
432
|
+
```ruby
|
433
|
+
# Problem: Not understanding what optimizations are applied
|
434
|
+
result = CSSminify2.compress_enhanced(css, options)
|
435
|
+
|
436
|
+
# Solution: Use statistics to understand what happened
|
437
|
+
stats = CSSminify2.compress_with_stats(css, options)
|
438
|
+
puts "Fallback used: #{stats[:statistics][:fallback_used]}"
|
439
|
+
puts "Selectors merged: #{stats[:statistics][:selectors_merged]}"
|
440
|
+
puts "Properties optimized: #{stats[:statistics][:properties_optimized]}"
|
441
|
+
|
442
|
+
if stats[:statistics][:fallback_used]
|
443
|
+
puts "⚠️ Enhanced compression failed, basic compression was used instead"
|
444
|
+
end
|
445
|
+
```
|
446
|
+
|
447
|
+
#### Issue: "Performance regression"
|
448
|
+
```ruby
|
449
|
+
# Problem: Enhanced features taking too long
|
450
|
+
# Solution: Use configuration presets and measure performance
|
451
|
+
|
452
|
+
start_time = Time.now
|
453
|
+
|
454
|
+
# Conservative approach for performance-critical builds
|
455
|
+
config = CSSminify2Enhanced::Configuration.conservative
|
456
|
+
config.optimize_shorthand_properties = true # Safe and fast
|
457
|
+
|
458
|
+
compressor = CSSminify2Enhanced::Compressor.new(config)
|
459
|
+
result = compressor.compress(css)
|
460
|
+
|
461
|
+
end_time = Time.now
|
462
|
+
puts "Compression took: #{(end_time - start_time) * 1000}ms"
|
463
|
+
```
|
464
|
+
|
465
|
+
### Migration Testing Strategy
|
466
|
+
|
467
|
+
#### 1. Gradual Rollout
|
468
|
+
```ruby
|
469
|
+
class GradualMigrationCompressor
|
470
|
+
def initialize
|
471
|
+
@use_enhanced = Rails.env.development? ||
|
472
|
+
ENV['CSS_ENHANCED_ENABLED'] == 'true'
|
473
|
+
end
|
474
|
+
|
475
|
+
def compress(css)
|
476
|
+
if @use_enhanced
|
477
|
+
# Test enhanced features in development
|
478
|
+
CSSminify2.compress_enhanced(css, {
|
479
|
+
optimize_shorthand_properties: true,
|
480
|
+
merge_duplicate_selectors: true
|
481
|
+
})
|
482
|
+
else
|
483
|
+
# Use stable compression in production
|
484
|
+
CSSminify2.compress(css)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
```
|
489
|
+
|
490
|
+
#### 2. A/B Testing
|
491
|
+
```ruby
|
492
|
+
class ABTestingCompressor
|
493
|
+
def compress(css)
|
494
|
+
# Compress with both methods
|
495
|
+
basic_result = CSSminify2.compress(css)
|
496
|
+
enhanced_result = CSSminify2.compress_enhanced(css, {
|
497
|
+
optimize_shorthand_properties: true,
|
498
|
+
merge_duplicate_selectors: true
|
499
|
+
})
|
500
|
+
|
501
|
+
# Log comparison metrics
|
502
|
+
basic_size = basic_result.length
|
503
|
+
enhanced_size = enhanced_result.length
|
504
|
+
improvement = ((basic_size - enhanced_size).to_f / basic_size * 100).round(2)
|
505
|
+
|
506
|
+
Rails.logger.info "CSS compression A/B test: #{improvement}% improvement with enhanced"
|
507
|
+
|
508
|
+
# Use enhanced if it provides significant improvement
|
509
|
+
improvement > 5 ? enhanced_result : basic_result
|
510
|
+
end
|
511
|
+
end
|
512
|
+
```
|
513
|
+
|
514
|
+
#### 3. Validation Testing
|
515
|
+
```ruby
|
516
|
+
# Create a comprehensive test to validate migration
|
517
|
+
class MigrationValidator
|
518
|
+
def self.validate_compression(css_files)
|
519
|
+
css_files.each do |file|
|
520
|
+
css = File.read(file)
|
521
|
+
|
522
|
+
# Test both methods
|
523
|
+
basic = CSSminify2.compress(css)
|
524
|
+
enhanced = CSSminify2.compress_enhanced(css, {
|
525
|
+
merge_duplicate_selectors: true,
|
526
|
+
optimize_shorthand_properties: true
|
527
|
+
})
|
528
|
+
|
529
|
+
# Validate results
|
530
|
+
puts "File: #{file}"
|
531
|
+
puts " Basic: #{basic.length} chars"
|
532
|
+
puts " Enhanced: #{enhanced.length} chars"
|
533
|
+
puts " Improvement: #{((basic.length - enhanced.length).to_f / basic.length * 100).round(2)}%"
|
534
|
+
|
535
|
+
# Check for obvious issues
|
536
|
+
if enhanced.count('{') != enhanced.count('}')
|
537
|
+
puts " ⚠️ WARNING: Unbalanced braces in enhanced result"
|
538
|
+
end
|
539
|
+
|
540
|
+
if enhanced.length > basic.length
|
541
|
+
puts " ⚠️ WARNING: Enhanced result is larger than basic"
|
542
|
+
end
|
543
|
+
|
544
|
+
puts ""
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
# Run validation
|
550
|
+
MigrationValidator.validate_compression(Dir.glob('app/assets/**/*.css'))
|
551
|
+
```
|
552
|
+
|
553
|
+
### Best Practices for Migration
|
554
|
+
|
555
|
+
1. **Start Small**: Begin with `optimize_shorthand_properties` only
|
556
|
+
2. **Test Thoroughly**: Validate in development and staging environments
|
557
|
+
3. **Monitor Performance**: Use statistics to track compression effectiveness
|
558
|
+
4. **Enable Gradually**: Add features one at a time to isolate any issues
|
559
|
+
5. **Plan Rollback**: Keep basic compression as fallback option
|
560
|
+
6. **Document Changes**: Record which features you enable and why
|
561
|
+
|
562
|
+
### Getting Help
|
563
|
+
|
564
|
+
If you encounter issues during migration:
|
565
|
+
|
566
|
+
1. **Enable debug mode**: Set `$VERBOSE = true` to see warnings
|
567
|
+
2. **Use strict error handling**: Enable detailed error messages
|
568
|
+
3. **Check statistics**: Look for `fallback_used` indicators
|
569
|
+
4. **Test with minimal CSS**: Isolate problematic CSS patterns
|
570
|
+
5. **Open an issue**: Report bugs with minimal reproducible examples
|
571
|
+
|
572
|
+
### Migration Checklist
|
573
|
+
|
574
|
+
- [ ] Update gemfile and run `bundle update`
|
575
|
+
- [ ] Test existing code works unchanged
|
576
|
+
- [ ] Enable `optimize_shorthand_properties`
|
577
|
+
- [ ] Test CSS output in target browsers
|
578
|
+
- [ ] Add `merge_duplicate_selectors` if beneficial
|
579
|
+
- [ ] Test complex CSS files (frameworks, etc.)
|
580
|
+
- [ ] Enable `compress_css_variables` for projects using CSS variables
|
581
|
+
- [ ] Add statistics monitoring to build process
|
582
|
+
- [ ] Enable `advanced_color_optimization` if no IE filter issues
|
583
|
+
- [ ] Test full production build pipeline
|
584
|
+
- [ ] Document final configuration for team
|
585
|
+
|
586
|
+
**Migration complete!** You're now using CSSminify2 v2.x with enhanced features.
|