Bläddra i källkod

added support of @media and @supports rules

Gildas 7 år sedan
förälder
incheckning
a0e6aae367
1 ändrade filer med 80 tillägg och 35 borttagningar
  1. 80 35
      lib/single-file/css-fonts-alt-minifier.js

+ 80 - 35
lib/single-file/css-fonts-alt-minifier.js

@@ -35,6 +35,7 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 	const REGEXP_FONT_SRC = /(.*?)\s*,?$/;
 	const EMPTY_URL_SOURCE = "url(\"data:base64,\")";
 	const LOCAL_SOURCE = "local(";
+	const MEDIA_ALL = "all";
 	const FONT_WEIGHTS = {
 		normal: "400",
 		bold: "700"
@@ -53,27 +54,80 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 
 	return {
 		process: (doc, stylesheets) => {
-			const fontsDetails = new Map();
+			const fontsDetails = {
+				fonts: new Map(),
+				medias: new Map(),
+				supports: new Map()
+			};
 			const stats = { rules: { processed: 0, discarded: 0 }, fonts: { processed: 0, discarded: 0 } };
+			let sheetIndex = 0;
 			stylesheets.forEach(stylesheetInfo => {
 				const cssRules = stylesheetInfo.stylesheet.children;
 				stats.rules.processed += cssRules.getSize();
 				stats.rules.discarded += cssRules.getSize();
-				getFontsDetails(doc, cssRules, fontsDetails);
+				if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
+					const mediaFontsDetails = createFontsDetailsInfo();
+					mediaFontsDetails.medias.set("media-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaFontsDetails);
+					getFontsDetails(doc, cssRules, sheetIndex, mediaFontsDetails);
+				} else {
+					getFontsDetails(doc, cssRules, sheetIndex, fontsDetails);
+				}
+				sheetIndex++;
 			});
 			processFontDetails(fontsDetails);
+			sheetIndex = 0;
 			stylesheets.forEach(stylesheetInfo => {
 				const cssRules = stylesheetInfo.stylesheet.children;
-				processFontFaceRules(cssRules, fontsDetails, "all", stats);
+				if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
+					processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + stylesheetInfo.mediaText), stats);
+				} else {
+					processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
+				}
 				stats.rules.discarded -= cssRules.getSize();
+				sheetIndex++;
 			});
 			return stats;
 		}
 	};
 
+	function getFontsDetails(doc, cssRules, sheetIndex, mediaFontsDetails) {
+		let mediaIndex = 0, supportsIndex = 0;
+		cssRules.forEach(cssRule => {
+			if (cssRule.type == "Atrule" && cssRule.name == "media" && cssRule.block && cssRule.block.children && cssRule.prelude) {
+				const mediaText = cssTree.generate(cssRule.prelude);
+				const fontsDetails = createFontsDetailsInfo();
+				mediaFontsDetails.medias.set("media-" + sheetIndex + "-" + mediaIndex + "-" + mediaText, fontsDetails);
+				mediaIndex++;
+				getFontsDetails(doc, cssRule.block.children, sheetIndex, fontsDetails);
+			} if (cssRule.type == "Atrule" && cssRule.name == "supports" && cssRule.block && cssRule.block.children && cssRule.prelude) {
+				const supportsText = cssTree.generate(cssRule.prelude);
+				const fontsDetails = createFontsDetailsInfo();
+				mediaFontsDetails.supports.set("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText, fontsDetails);
+				supportsIndex++;
+				getFontsDetails(doc, cssRule.block.children, sheetIndex, fontsDetails);
+			} else {
+				if (cssRule.type == "Atrule" && cssRule.name == "font-face") {
+					const fontKey = getFontKey(cssRule);
+					let fontInfo = mediaFontsDetails.fonts.get(fontKey);
+					if (!fontInfo) {
+						fontInfo = [];
+						mediaFontsDetails.fonts.set(fontKey, fontInfo);
+					}
+					const src = getPropertyValue(cssRule, "src");
+					if (src) {
+						const fontSources = src.match(REGEXP_URL_FUNCTION);
+						if (fontSources) {
+							fontSources.forEach(source => fontInfo.unshift(source));
+						}
+					}
+				}
+			}
+		});
+	}
+
 	function processFontDetails(fontsDetails) {
-		fontsDetails.forEach((fontInfo, fontKey) => {
-			fontsDetails.set(fontKey, fontInfo.map(fontSource => {
+		fontsDetails.fonts.forEach((fontInfo, fontKey) => {
+			fontsDetails.fonts.set(fontKey, fontInfo.map(fontSource => {
 				const fontFormatMatch = fontSource.match(REGEXP_FONT_FORMAT_VALUE);
 				let fontFormat;
 				const urlMatch = fontSource.match(REGEXP_URL_SIMPLE_QUOTES_FN) ||
@@ -103,19 +157,26 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 				return { src: fontSource.match(REGEXP_FONT_SRC)[1], fontUrl, format: fontFormat };
 			}));
 		});
+		fontsDetails.medias.forEach(mediaFontsDetails => processFontDetails(mediaFontsDetails));
 	}
 
-	function processFontFaceRules(cssRules, fontsDetails, media, stats) {
+	function processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats) {
 		const removedRules = [];
+		let mediaIndex = 0, supportsIndex = 0;
 		for (let cssRule = cssRules.head; cssRule; cssRule = cssRule.next) {
 			const ruleData = cssRule.data;
-			if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block && ruleData.prelude && ruleData.prelude.children) {
+			if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block && ruleData.block.children && ruleData.prelude) {
 				const mediaText = cssTree.generate(ruleData.prelude);
-				processFontFaceRules(ruleData.block.children, fontsDetails, mediaText, stats);
-			} else if (ruleData.type == "Atrule" && ruleData.name == "font-face" && (media.includes("all") || media.includes("screen"))) {
-				const fontInfo = fontsDetails.get(getFontKey(ruleData));
+				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);
+				supportsIndex++;
+			} else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
+				const fontInfo = fontsDetails.fonts.get(getFontKey(ruleData));
 				if (fontInfo) {
-					fontsDetails.delete(getFontKey(ruleData));
+					fontsDetails.fonts.delete(getFontKey(ruleData));
 					processFontFaceRule(ruleData, fontInfo, stats);
 				} else {
 					removedRules.push(cssRule);
@@ -171,30 +232,6 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 		}
 	}
 
-	function getFontsDetails(doc, cssRules, fontsDetails) {
-		cssRules.forEach(cssRule => {
-			if (cssRule.type == "Atrule" && cssRule.name == "media" && cssRule.block) {
-				getFontsDetails(doc, cssRule.block.children, fontsDetails);
-			} else {
-				if (cssRule.type == "Atrule" && cssRule.name == "font-face") {
-					const fontKey = getFontKey(cssRule);
-					let fontInfo = fontsDetails.get(fontKey);
-					if (!fontInfo) {
-						fontInfo = [];
-						fontsDetails.set(fontKey, fontInfo);
-					}
-					const src = getPropertyValue(cssRule, "src");
-					if (src) {
-						const fontSources = src.match(REGEXP_URL_FUNCTION);
-						if (fontSources) {
-							fontSources.forEach(source => fontInfo.unshift(source));
-						}
-					}
-				}
-			}
-		});
-	}
-
 	function getFontKey(cssRule) {
 		return JSON.stringify([
 			getFontFamily(getPropertyValue(cssRule, "font-family")),
@@ -226,4 +263,12 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 		return FONT_STRETCHES[stretch] || stretch;
 	}
 
+	function createFontsDetailsInfo() {
+		return {
+			fonts: new Map(),
+			medias: new Map(),
+			supports: new Map()
+		};
+	}
+
 })();