Pārlūkot izejas kodu

Add offenders to imageOptimization

Gaël Métais 10 gadi atpakaļ
vecāks
revīzija
9ccca3b33b

+ 24 - 4
front/src/css/rule.css

@@ -164,16 +164,18 @@
   font-style: italic;
   font-style: italic;
   font-weight: normal;
   font-weight: normal;
 }
 }
-.colorPalette {
-  width: 30em;
-  border: 2px solid #000;
-  text-align: left;
+.checker {
   /* Checkerboard background */
   /* Checkerboard background */
   background-color: #ddd;
   background-color: #ddd;
   background-image: linear-gradient(45deg, #aaaaaa 25%, transparent 25%, transparent 75%, #aaaaaa 75%, #aaaaaa), linear-gradient(45deg, #aaaaaa 25%, transparent 25%, transparent 75%, #aaaaaa 75%, #aaaaaa);
   background-image: linear-gradient(45deg, #aaaaaa 25%, transparent 25%, transparent 75%, #aaaaaa 75%, #aaaaaa), linear-gradient(45deg, #aaaaaa 25%, transparent 25%, transparent 75%, #aaaaaa 75%, #aaaaaa);
   background-size: 1em 1em;
   background-size: 1em 1em;
   background-position: 0 0, 0.5em 0.5em;
   background-position: 0 0, 0.5em 0.5em;
 }
 }
+.colorPalette {
+  width: 30em;
+  border: 2px solid #000;
+  text-align: left;
+}
 .colorPalette > div {
 .colorPalette > div {
   display: inline-block;
   display: inline-block;
   height: 2em;
   height: 2em;
@@ -216,3 +218,21 @@
   font-weight: bold;
   font-weight: bold;
   color: #e74c3c;
   color: #e74c3c;
 }
 }
+.imageOffenders {
+  display: table;
+  border-spacing: 3em;
+  width: 90%;
+}
+.imageOffenders > div {
+  display: table-row;
+}
+.imageOffenders > div > div {
+  display: table-cell;
+  vertical-align: middle;
+}
+.imageOffenders img {
+  max-height: 10em;
+  max-width: 40em;
+  border: 1px solid #000;
+  margin-top: 0.5em;
+}

+ 4 - 0
front/src/js/directives/offendersDirectives.js

@@ -864,6 +864,10 @@
             
             
             var kilo = bytes / 1024;
             var kilo = bytes / 1024;
 
 
+            if (kilo < 1) {
+                return bytes + ' Bytes';
+            }
+
             if (kilo < 100) {
             if (kilo < 100) {
                 return kilo.toFixed(1) + ' KB';
                 return kilo.toFixed(1) + ' KB';
             }
             }

+ 29 - 5
front/src/less/rule.less

@@ -176,16 +176,18 @@
     }
     }
 }
 }
 
 
-.colorPalette {
-    width: 30em;
-    border: 2px solid #000;
-    text-align: left;
-
+.checker {
     /* Checkerboard background */
     /* Checkerboard background */
     background-color: #ddd;
     background-color: #ddd;
     background-image: linear-gradient(45deg, #AAA 25%, transparent 25%, transparent 75%, #AAA 75%, #AAA), linear-gradient(45deg, #AAA 25%, transparent 25%, transparent 75%, #AAA 75%, #AAA);
     background-image: linear-gradient(45deg, #AAA 25%, transparent 25%, transparent 75%, #AAA 75%, #AAA), linear-gradient(45deg, #AAA 25%, transparent 25%, transparent 75%, #AAA 75%, #AAA);
     background-size:1em 1em;
     background-size:1em 1em;
     background-position:0 0, 0.5em 0.5em;
     background-position:0 0, 0.5em 0.5em;
+}
+
+.colorPalette {
+    width: 30em;
+    border: 2px solid #000;
+    text-align: left;
 
 
     > div {
     > div {
         display: inline-block;
         display: inline-block;
@@ -235,4 +237,26 @@
 .hugeFile {
 .hugeFile {
     font-weight: bold;
     font-weight: bold;
     color: #e74c3c;
     color: #e74c3c;
+}
+
+.imageOffenders {
+    display: table;
+    border-spacing: 3em;
+    width: 90%;
+
+    > div {
+        display: table-row;
+
+        > div {
+            display: table-cell;
+            vertical-align: middle;
+        }
+    }
+
+    img {
+        max-height: 10em;
+        max-width: 40em;
+        border: 1px solid #000;
+        margin-top: 0.5em;
+    }
 }
 }

+ 18 - 1
front/src/views/rule.html

@@ -190,7 +190,7 @@
 
 
             <div ng-if="policyName === 'cssColors' && rule.offendersObj.count > 0">
             <div ng-if="policyName === 'cssColors' && rule.offendersObj.count > 0">
                 <p>This is the colors palette, sized by total occurrences:</p>
                 <p>This is the colors palette, sized by total occurrences:</p>
-                <div class="colorPalette">
+                <div class="colorPalette checker">
                     <div ng-repeat="offender in rule.offendersObj.palette" style="background-color: {{offender.color}}; width: {{offender.occurrences * 100 / rule.offendersObj.palette[0].occurrences}}%"><div>{{offender.color}} ({{offender.occurrences}} times)</div></div>
                     <div ng-repeat="offender in rule.offendersObj.palette" style="background-color: {{offender.color}}; width: {{offender.occurrences * 100 / rule.offendersObj.palette[0].occurrences}}%"><div>{{offender.color}} ({{offender.occurrences}} times)</div></div>
                 </div>
                 </div>
             </div>
             </div>
@@ -213,6 +213,23 @@
         </div>
         </div>
     </div>
     </div>
 
 
+    <div ng-if="policyName === 'imageOptimization'">
+        <h3 ng-if="rule.value > 0">{{rule.value | bytes}} could be saved on <ng-pluralize count="rule.offendersObj.list.images.length" when="{'one': '1 image', 'other': '{} images'}"></ng-pluralize></h3>
+        <div class="imageOffenders">
+            <div ng-repeat="image in rule.offendersObj.list.images | orderBy:'-gain'">
+                <div>
+                    Current file: <url-link url="image.url" max-length="50"></url-link>
+                    <div><a href="{{image.url}}" target="_blank"><img ng-src="{{image.url}}" class="checker" /></a></div>
+                </div>
+                <div>
+                    <p>Current weight: {{image.original | bytes}}</p>
+                    <p ng-if="image.lossless">With a lossless optimization:<br/>{{image.lossless | bytes}} (<b>-{{image.original - image.lossless | bytes}}</b>)</p>
+                    <p ng-if="image.lossy">With a lossy optimization:<br/>{{image.lossy | bytes}} (<b>-{{image.original - image.lossy | bytes}}</b>)</p>
+                </div>
+            </div>
+        </div>
+    </div>
+
     <div ng-if="policyName === 'DOMaccesses'">
     <div ng-if="policyName === 'DOMaccesses'">
         <h3>{{rule.value}} offenders</h3>
         <h3>{{rule.value}} offenders</h3>
         Please open the <a href="/result/{{runId}}/timeline">JS timeline</a>
         Please open the <a href="/result/{{runId}}/timeline">JS timeline</a>

+ 1 - 1
lib/metadata/policies.js

@@ -865,7 +865,7 @@ var policies = {
     "imageOptimization": {
     "imageOptimization": {
         "tool": "weightChecker",
         "tool": "weightChecker",
         "label": "Image optimization",
         "label": "Image optimization",
-        "message": "<p>This metric mesures the number of bytes that could be saved by optimizing images.</p><p>Image optimization is generally one of the easiest way to reduce a page weight, and as a result, the page load time. Don't use Photoshop or other image editing tools, they lie to you because they're generally not very good for optimization. Use specialized tools such as <a href=\"https://kraken.io/\" target=\"_blank\">Kraken.io</a> or the excellent <a href=\"https://imageoptim.com/\" target=\"_blank\">ImageOption</a> on Mac.</p><p>The tools in use in YellowLabTools are not set to their maximum optimization power, so you might be able to compress even more (the max JPEG quality is set to 85, which should be sufficient for any website).</p>",
+        "message": "<p>This metric mesures the number of bytes that could be saved by optimizing images.</p><p>Image optimization is generally one of the easiest way to reduce a page weight, and as a result, the page load time. Don't use Photoshop or other image editing tools, they're not very good for optimization. Use specialized tools such as <a href=\"https://kraken.io/\" target=\"_blank\">Kraken.io</a> or the excellent <a href=\"https://imageoptim.com/\" target=\"_blank\">ImageOption</a> on Mac. For SVG images, you can use <a href=\"https://jakearchibald.github.io/svgomg/\" target=\"_blank\">SVGOMG</a></p><p>The tools in use in YellowLabTools are not set to their maximum optimization power, so you might be able to compress even more.</p>",
         "isOkThreshold": 30720,
         "isOkThreshold": 30720,
         "isBadThreshold": 122880,
         "isBadThreshold": 122880,
         "isAbnormalThreshold": 204800,
         "isAbnormalThreshold": 204800,

+ 3 - 1
lib/tools/weightChecker/imageOptimizer.js

@@ -149,10 +149,12 @@ var ImageOptimizer = function() {
         return deferred.promise;
         return deferred.promise;
     }
     }
 
 
+    // The gain is estimated of enough value if it's over 2KB or over 20%,
+    // but it's ignored if is below 100 bytes
     function gainIsEnough(oldWeight, newWeight) {
     function gainIsEnough(oldWeight, newWeight) {
         var gain = oldWeight - newWeight;
         var gain = oldWeight - newWeight;
         var ratio = gain / oldWeight;
         var ratio = gain / oldWeight;
-        return (gain > 2048 || ratio > 0.2);
+        return (gain > 2048 || (ratio > 0.2 && gain > 100));
     }
     }
 
 
     function isJpeg(entry) {
     function isJpeg(entry) {

+ 3 - 32
lib/tools/weightChecker/weightChecker.js

@@ -140,45 +140,16 @@ var WeightChecker = function() {
     function listImageNotOptimized(requests) {
     function listImageNotOptimized(requests) {
         var results = {
         var results = {
             totalGain: 0,
             totalGain: 0,
-            byType: {
-                jpeg: {
-                    totalGain: 0,
-                    requests: []
-                },
-                png: {
-                    totalGain: 0,
-                    requests: []
-                },
-                svg: {
-                    totalGain: 0,
-                    requests: []
-                }
-            }
+            images: []
         };
         };
 
 
         requests.forEach(function(req) {
         requests.forEach(function(req) {
-            var type = null;
-
-            switch(req.contentType) {
-                case 'image/jpeg':
-                    type = 'jpeg';
-                    break;
-                case 'image/png':
-                    type = 'png';
-                    break;
-                case 'image/svg+xml':
-                    type = 'svg';
-                    break;
-            }
-
-            if (type && req.weightCheck.bodySize && req.weightCheck.isOptimized === false) {
+            if (req.weightCheck.bodySize && req.weightCheck.isOptimized === false) {
                 var gain = req.weightCheck.bodySize - req.weightCheck.optimized;
                 var gain = req.weightCheck.bodySize - req.weightCheck.optimized;
 
 
                 results.totalGain += gain;
                 results.totalGain += gain;
 
 
-                results.byType[type].totalGain += gain;
-
-                results.byType[type].requests.push({
+                results.images.push({
                     url: req.url,
                     url: req.url,
                     original: req.weightCheck.bodySize,
                     original: req.weightCheck.bodySize,
                     optimized: req.weightCheck.optimized,
                     optimized: req.weightCheck.optimized,

+ 2 - 1
test/core/imageOptimizerTest.js

@@ -309,7 +309,8 @@ describe('imageOptimizer', function() {
         imageOptimizer.gainIsEnough(20000, 21000).should.equal(false);
         imageOptimizer.gainIsEnough(20000, 21000).should.equal(false);
         imageOptimizer.gainIsEnough(20000, 40000).should.equal(false);
         imageOptimizer.gainIsEnough(20000, 40000).should.equal(false);
         imageOptimizer.gainIsEnough(20000, 19500).should.equal(false);
         imageOptimizer.gainIsEnough(20000, 19500).should.equal(false);
-        imageOptimizer.gainIsEnough(200, 100).should.equal(true);
+        imageOptimizer.gainIsEnough(250, 120).should.equal(true);
+        imageOptimizer.gainIsEnough(200, 120).should.equal(false);
         imageOptimizer.gainIsEnough(2000, 1900).should.equal(false);
         imageOptimizer.gainIsEnough(2000, 1900).should.equal(false);
         imageOptimizer.gainIsEnough(200000, 197000).should.equal(true);
         imageOptimizer.gainIsEnough(200000, 197000).should.equal(true);
     });
     });

+ 1 - 2
test/core/weightCheckerTest.js

@@ -87,8 +87,7 @@ describe('weightChecker', function() {
 
 
             data.toolsResults.weightChecker.offenders.should.have.a.property('imageOptimization');
             data.toolsResults.weightChecker.offenders.should.have.a.property('imageOptimization');
             data.toolsResults.weightChecker.offenders.imageOptimization.totalGain.should.be.above(0);
             data.toolsResults.weightChecker.offenders.imageOptimization.totalGain.should.be.above(0);
-            data.toolsResults.weightChecker.offenders.imageOptimization.byType.jpeg.requests.length.should.equal(1);
-            data.toolsResults.weightChecker.offenders.imageOptimization.byType.svg.requests.length.should.equal(1);
+            data.toolsResults.weightChecker.offenders.imageOptimization.images.length.should.equal(2);
 
 
             done();
             done();
         })
         })