|
|
@@ -21,10 +21,14 @@
|
|
|
* Source.
|
|
|
*/
|
|
|
|
|
|
+/* global window */
|
|
|
+
|
|
|
this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fontsAltMinifier || (() => {
|
|
|
|
|
|
const singlefile = this.singlefile;
|
|
|
|
|
|
+ const FontFace = window.FontFace;
|
|
|
+
|
|
|
const REGEXP_URL_SIMPLE_QUOTES_FN = /url\s*\(\s*'(.*?)'\s*\)/i;
|
|
|
const REGEXP_URL_DOUBLE_QUOTES_FN = /url\s*\(\s*"(.*?)"\s*\)/i;
|
|
|
const REGEXP_URL_NO_QUOTES_FN = /url\s*\(\s*(.*?)\s*\)/i;
|
|
|
@@ -57,7 +61,7 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
|
|
|
};
|
|
|
|
|
|
return {
|
|
|
- process: (doc, stylesheets) => {
|
|
|
+ process: async (doc, stylesheets) => {
|
|
|
const fontsDetails = {
|
|
|
fonts: new Map(),
|
|
|
medias: new Map(),
|
|
|
@@ -81,20 +85,18 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
|
|
|
sheetIndex++;
|
|
|
});
|
|
|
processFontDetails(fontsDetails);
|
|
|
- sheetIndex = 0;
|
|
|
- stylesheets.forEach(stylesheetInfo => {
|
|
|
+ await Promise.all([...stylesheets].map(async ([, stylesheetInfo], sheetIndex) => {
|
|
|
const cssRules = stylesheetInfo.stylesheet.children;
|
|
|
const media = stylesheetInfo.mediaText;
|
|
|
if (cssRules) {
|
|
|
if (media && media != MEDIA_ALL) {
|
|
|
- processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), stats);
|
|
|
+ await processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), stats);
|
|
|
} else {
|
|
|
- processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
|
|
|
+ await processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
|
|
|
}
|
|
|
stats.rules.discarded -= cssRules.getSize();
|
|
|
}
|
|
|
- sheetIndex++;
|
|
|
- });
|
|
|
+ }));
|
|
|
return stats;
|
|
|
}
|
|
|
};
|
|
|
@@ -168,7 +170,7 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
|
|
|
fontsDetails.medias.forEach(mediaFontsDetails => processFontDetails(mediaFontsDetails));
|
|
|
}
|
|
|
|
|
|
- function processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats) {
|
|
|
+ async function processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats) {
|
|
|
const cssTree = singlefile.lib.vendor.cssTree;
|
|
|
const removedRules = [];
|
|
|
let mediaIndex = 0, supportsIndex = 0;
|
|
|
@@ -176,17 +178,17 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
|
|
|
const ruleData = cssRule.data;
|
|
|
if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block && ruleData.block.children && ruleData.prelude) {
|
|
|
const mediaText = cssTree.generate(ruleData.prelude);
|
|
|
- processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + mediaIndex + "-" + mediaText), stats);
|
|
|
+ await processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + mediaIndex + "-" + mediaText), stats);
|
|
|
mediaIndex++;
|
|
|
} else if (ruleData.type == "Atrule" && ruleData.name == "supports" && ruleData.block && ruleData.block.children && ruleData.prelude) {
|
|
|
const supportsText = cssTree.generate(ruleData.prelude);
|
|
|
- processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.supports.get("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText), stats);
|
|
|
+ await processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.supports.get("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText), stats);
|
|
|
supportsIndex++;
|
|
|
} else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
|
|
|
const fontInfo = fontsDetails.fonts.get(getFontKey(ruleData));
|
|
|
if (fontInfo) {
|
|
|
fontsDetails.fonts.delete(getFontKey(ruleData));
|
|
|
- processFontFaceRule(ruleData, fontInfo, stats);
|
|
|
+ await processFontFaceRule(ruleData, fontInfo, stats);
|
|
|
} else {
|
|
|
removedRules.push(cssRule);
|
|
|
}
|
|
|
@@ -195,17 +197,31 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
|
|
|
removedRules.forEach(cssRule => cssRules.remove(cssRule));
|
|
|
}
|
|
|
|
|
|
- function processFontFaceRule(ruleData, fontInfo, stats) {
|
|
|
+ async function processFontFaceRule(ruleData, fontInfo, stats) {
|
|
|
const cssTree = singlefile.lib.vendor.cssTree;
|
|
|
- const findSource = fontFormat => fontInfo.find(source => !source.src.match(EMPTY_URL_SOURCE) && !source.src.match(TEXT_CONTENT_URL_SOURCE) && source.format == fontFormat);
|
|
|
+ await Promise.all(fontInfo.map(async source => {
|
|
|
+ if (FontFace) {
|
|
|
+ const fontFace = new FontFace("test-font", source.src);
|
|
|
+ try {
|
|
|
+ await fontFace.load();
|
|
|
+ await fontFace.loaded;
|
|
|
+ source.valid = true;
|
|
|
+ } catch (error) {
|
|
|
+ // ignored
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ source.valid = true;
|
|
|
+ }
|
|
|
+ }));
|
|
|
+ const findSource = (fontFormat, testValidity) => fontInfo.find(source => !source.src.match(EMPTY_URL_SOURCE) && !source.src.match(TEXT_CONTENT_URL_SOURCE) && source.format == fontFormat && (!testValidity || source.valid));
|
|
|
const filterSource = fontSource => fontInfo.filter(source => source == fontSource || source.src.startsWith(LOCAL_SOURCE));
|
|
|
stats.fonts.processed += fontInfo.length;
|
|
|
stats.fonts.discarded += fontInfo.length;
|
|
|
- const woffFontFound = findSource("woff2-variations") || findSource("woff2") || findSource("woff");
|
|
|
+ const woffFontFound = findSource("woff2-variations", true) || findSource("woff2", true) || findSource("woff", true);
|
|
|
if (woffFontFound) {
|
|
|
fontInfo = filterSource(woffFontFound);
|
|
|
} else {
|
|
|
- const ttfFontFound = findSource("truetype-variations") || findSource("truetype");
|
|
|
+ const ttfFontFound = findSource("truetype-variations", true) || findSource("truetype", true);
|
|
|
if (ttfFontFound) {
|
|
|
fontInfo = filterSource(ttfFontFound);
|
|
|
} else {
|