Detect non WOFF2 fonts and estimate gain
This commit is contained in:
@@ -483,6 +483,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="policyName === 'nonWoff2Fonts'">
|
||||
<h3 ng-if="rule.value > 0">{{rule.value | bytes}} could be saved on <ng-pluralize count="rule.offendersObj.list.fonts.length" when="{'one': '1 file', 'other': '{} files'}"></ng-pluralize></h3>
|
||||
<div class="table">
|
||||
<div class="headers">
|
||||
<div>File</div>
|
||||
<div>Current weight</div>
|
||||
<div>Woff 2 weight</div>
|
||||
<div>Gain</div>
|
||||
</div>
|
||||
<div ng-repeat="file in rule.offendersObj.list.fonts | orderBy:'-gain'">
|
||||
<div>
|
||||
<url-link url="file.url" max-length="70"></url-link>
|
||||
</div>
|
||||
<div>{{file.originalSize | bytes}}</div>
|
||||
<div>{{file.woff2Size | bytes}}</div>
|
||||
<div><b>-{{file.gain | bytes}}</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="policyName === 'http2'">
|
||||
<h3>Protocols advertised by the server</h3>
|
||||
<div class="offendersTable">
|
||||
|
||||
@@ -927,6 +927,16 @@ var policies = {
|
||||
return offenders;
|
||||
}
|
||||
},*/
|
||||
"nonWoff2Fonts": {
|
||||
"tool": "redownload",
|
||||
"label": "Woff 2",
|
||||
"message": "<p>The fonts listed here could be lighter if they were served with the latest woff 2 font file format. Some online tools can help you easily convert older formats to woff 2.</p>",
|
||||
"isOkThreshold": 0,
|
||||
"isBadThreshold": 61440,
|
||||
"isAbnormalThreshold": 122880,
|
||||
"hasOffenders": true,
|
||||
"unit": 'bytes'
|
||||
},
|
||||
"oldHttpProtocol": {
|
||||
"label": "HTTP/1 requests",
|
||||
"message": "<p>HTTP/2 is the latest version of the HTTP protocol. It is designed to optimize load speed. HTTP/3 will come soon and should be even faster!</p><p>When a domain sends more than 4 requests over HTTP/1, this metric counts one point for each new request. Below 5 requests, the benefits of HTTP/2 are generally less significant.</p>",
|
||||
|
||||
@@ -87,7 +87,9 @@
|
||||
"label": "Web fonts",
|
||||
"policies": {
|
||||
"fontsCount": 1,
|
||||
"heavyFonts": 1
|
||||
"heavyFonts": 0.5,
|
||||
//"unusedUnicodeRanges": 0.5,
|
||||
"nonWoff2Fonts": 0.5
|
||||
}
|
||||
},
|
||||
"serverConfig": {
|
||||
|
||||
@@ -15,9 +15,6 @@ var ContentTypeChecker = function() {
|
||||
|
||||
function checkContentType(entry) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
debug('Entering contentTypeChecker');
|
||||
debug(entry);
|
||||
|
||||
// Setting isSomething values:
|
||||
switch(entry.type) {
|
||||
@@ -59,9 +56,15 @@ var ContentTypeChecker = function() {
|
||||
try {
|
||||
foundType = findContentType(entry.weightCheck.bodyBuffer);
|
||||
|
||||
if (foundType !== null && foundType.type !== entry.type) {
|
||||
debug('Content type %s is wrong for %s. It should be %s.', entry.type, entry.ulr, foundType.type);
|
||||
rewriteContentType(entry, foundType);
|
||||
if (foundType !== null) {
|
||||
if (foundType.type === 'webfont') {
|
||||
// Always rewrite fonts for woff2 checking
|
||||
rewriteContentType(entry, foundType);
|
||||
} else if (foundType.type !== entry.type) {
|
||||
// For other kind of files, just rewrite if needed
|
||||
debug('Content type %s is wrong for %s. It should be %s.', entry.type, entry.ulr, foundType.type);
|
||||
rewriteContentType(entry, foundType);
|
||||
}
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
@@ -188,6 +191,7 @@ var ContentTypeChecker = function() {
|
||||
updateFn: function(entry) {
|
||||
entry.type = 'webfont';
|
||||
entry.isWebFont = true;
|
||||
entry.isWoff = true;
|
||||
}
|
||||
},
|
||||
woff2: {
|
||||
@@ -196,6 +200,7 @@ var ContentTypeChecker = function() {
|
||||
updateFn: function(entry) {
|
||||
entry.type = 'webfont';
|
||||
entry.isWebFont = true;
|
||||
entry.isWoff2 = true;
|
||||
}
|
||||
},
|
||||
otf: {
|
||||
@@ -212,6 +217,7 @@ var ContentTypeChecker = function() {
|
||||
updateFn: function(entry) {
|
||||
entry.type = 'webfont';
|
||||
entry.isWebFont = true;
|
||||
entry.isTTF = true;
|
||||
}
|
||||
},
|
||||
eot: {
|
||||
|
||||
@@ -2,6 +2,8 @@ var debug = require('debug')('ylt:fontAnalyzer');
|
||||
|
||||
var Q = require('q');
|
||||
var fontkit = require('fontkit');
|
||||
var woffTools = require('woff-tools');
|
||||
var ttf2woff2 = require('ttf2woff2');
|
||||
|
||||
var FontAnalyzer = function() {
|
||||
|
||||
@@ -19,25 +21,100 @@ var FontAnalyzer = function() {
|
||||
if (entry.isWebFont) {
|
||||
debug('File %s is a font. Let\'s have a look inside!', entry.url);
|
||||
|
||||
getMetricsFromFont(entry, charsListOnPage)
|
||||
convertToWoff2(entry)
|
||||
|
||||
.then(function(entry) {
|
||||
return getMetricsFromFont(entry, charsListOnPage);
|
||||
})
|
||||
|
||||
.then(function(fontMetrics) {
|
||||
entry.fontMetrics = fontMetrics;
|
||||
deferred.resolve(entry);
|
||||
})
|
||||
|
||||
.fail(function(error) {
|
||||
debug('Could not open the font: %s', error);
|
||||
deferred.resolve(entry);
|
||||
});
|
||||
|
||||
} else {
|
||||
deferred.resolve(entry);
|
||||
}
|
||||
|
||||
deferred.resolve(entry);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function convertToWoff2(entry) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
debug('Entering font format converter...');
|
||||
|
||||
if (entry.isWoff2) {
|
||||
|
||||
debug('File is already a woff2.');
|
||||
deferred.resolve(entry);
|
||||
|
||||
} else if (entry.isWoff) {
|
||||
|
||||
debug('File is a woff. Let\'s convert to woff2');
|
||||
|
||||
try {
|
||||
|
||||
var fileSize = entry.weightCheck.bodySize;
|
||||
debug('Current file size is %d', fileSize);
|
||||
|
||||
var ttf = woffTools.toSfnt(entry.weightCheck.bodyBuffer);
|
||||
var woff2 = ttf2woff2(ttf);
|
||||
|
||||
var newFileSize = woff2.length;
|
||||
|
||||
debug('New image size is %d', newFileSize);
|
||||
debug('Filesize is %d bytes smaller (-%d%)', fileSize - newFileSize, Math.round((fileSize - newFileSize) * 100 / fileSize));
|
||||
entry.weightCheck.sizeAsWoff2 = newFileSize;
|
||||
|
||||
deferred.resolve(entry);
|
||||
|
||||
} catch(error) {
|
||||
deferred.reject(error);
|
||||
}
|
||||
|
||||
} else if (entry.isTtf) {
|
||||
|
||||
debug('File is a TTF. Let\'s convert to woff2');
|
||||
|
||||
try {
|
||||
|
||||
var fileSize = entry.weightCheck.bodySize;
|
||||
debug('Current file size is %d', fileSize);
|
||||
|
||||
var woff2 = ttf2woff2(entry.weightCheck.bodyBuffer);
|
||||
|
||||
var newFileSize = woff2.length;
|
||||
|
||||
debug('New image size is %d', newFileSize);
|
||||
debug('Filesize is %d bytes smaller (-%d%)', fileSize - newFileSize, Math.round((fileSize - newFileSize) * 100 / fileSize));
|
||||
entry.weightCheck.sizeAsWoff2 = newFileSize;
|
||||
|
||||
deferred.resolve(entry);
|
||||
|
||||
} catch(error) {
|
||||
deferred.reject(error);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Other font formats are not handled
|
||||
deferred.resolve(entry);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
// The gain is estimated of enough value if it's over 1KB or over 20%,
|
||||
// but it's ignored if is below 100 bytes
|
||||
function gainIsEnough(oldWeight, newWeight) {
|
||||
var gain = oldWeight - newWeight;
|
||||
var ratio = gain / oldWeight;
|
||||
return (gain > 2048 || (ratio > 0.2 && gain > 100));
|
||||
}
|
||||
|
||||
function getMetricsFromFont(entry, charsListOnPage) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
|
||||
@@ -167,6 +167,10 @@ var Redownload = function() {
|
||||
offenders.fontsCount = listFonts(results);
|
||||
metrics.fontsCount = offenders.fontsCount.count;
|
||||
|
||||
// Conversion to woff2
|
||||
offenders.nonWoff2Fonts = listNonWoff2Fonts(results);
|
||||
metrics.nonWoff2Fonts = offenders.nonWoff2Fonts.totalGain;
|
||||
|
||||
// Heavy fonts
|
||||
offenders.heavyFonts = listHeavyFonts(results);
|
||||
metrics.heavyFonts = offenders.heavyFonts.totalGain;
|
||||
@@ -551,6 +555,42 @@ var Redownload = function() {
|
||||
};
|
||||
}
|
||||
|
||||
function listNonWoff2Fonts(requests) {
|
||||
var results = {
|
||||
totalGain: 0,
|
||||
fonts: []
|
||||
};
|
||||
|
||||
requests.forEach(function(req) {
|
||||
if (!req.isWoff2 && req.weightCheck.sizeAsWoff2) {
|
||||
var before = req.weightCheck.bodySize;
|
||||
var after = req.weightCheck.sizeAsWoff2;
|
||||
var gain = before - after;
|
||||
|
||||
var type = null;
|
||||
if (req.isWoff) {
|
||||
type = 'woff';
|
||||
} else if (req.isTtf) {
|
||||
type = 'ttf';
|
||||
}
|
||||
|
||||
if (gain > 200) {
|
||||
results.totalGain += gain;
|
||||
|
||||
results.fonts.push({
|
||||
url: req.url,
|
||||
originalSize: before,
|
||||
type: type,
|
||||
woff2Size: after,
|
||||
gain: gain
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function listHeavyFonts(requests) {
|
||||
var list = [];
|
||||
var totalGain = 0;
|
||||
|
||||
+3
-1
@@ -67,7 +67,9 @@
|
||||
"request": "2.88.0",
|
||||
"rimraf": "2.6.3",
|
||||
"temporary": "0.0.8",
|
||||
"uglify-js": "3.4.9"
|
||||
"ttf2woff2": "3.0.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"woff-tools": "0.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "~4.2.0",
|
||||
|
||||
Reference in New Issue
Block a user