UNPKG

postcss-bgimage

Version:

Plugin for PoscCSS to remove or keep only images by url() to optimize page loading

220 lines (180 loc) 5.9 kB
'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var postcss = _interopDefault(require('postcss')); var cssColorList = _interopDefault(require('css-color-list')); const PATTERN_IGNORE = /[\s]*bgImage[\s]*:[\s]*ignore[\s]*/i; /** * Checks instruction to ignore the node. * * @param {Node} node * * @returns {boolean} */ function isNodeIgnored(node) { const { parent } = node; if (!parent) { // Root was reached. return false; } if (parent.some(child => child.type === 'comment' && PATTERN_IGNORE.test(child.text))) { // Instruction to ignore the node was detected. return true; } // Check the instruction on one level above. return isNodeIgnored(parent); } const PATTERN_BACKGROUND = /background(?!-)/i; const PATTERN_GRADIENT = /[a-z-]*gradient\((?:(?:hls|rgb)a?\([^()]*\)[^,]*[,]?|[^,]+[,]?)+\)/i; const PATTERN_URL = /url\([^)]+\)[\s]*/i; // @see https://developer.mozilla.org/en-US/docs/Web/CSS/background-color const colorList = cssColorList(); const PATTERN_COLOR = `(?:(?:rgb|hls)a?\\([^)]*\\)|#[0-9a-f]{3,8}|${colorList.join('|')})`; const PATTERN_START_BACKGROUND_COLOR = new RegExp(`^${PATTERN_COLOR}[\\s]*`, 'i'); const PATTERN_END_BACKGROUND_COLOR = new RegExp(`[\\s]*${PATTERN_COLOR}$`, 'i'); /** * Destruction of shorthand 'background' by prop 'background-image' and the rest props. * * @param {string} css */ function destructShorthand(css) { css.walkDecls(PATTERN_BACKGROUND, decl => { if (!isNodeIgnored(decl)) { const { value } = decl; const hasURL = PATTERN_URL.test(value); if (hasURL) { let valueStartBgColor = ''; let valueEndBgColor = ''; const layers = value.replace(PATTERN_START_BACKGROUND_COLOR, match => { valueStartBgColor = match; return ''; }).replace(PATTERN_END_BACKGROUND_COLOR, match => { valueEndBgColor = match; return ''; }).split(/,/).reduce((result, subLine, index) => { if (index === 0) { return [subLine]; } const indexLast = result.length - 1; const subLineLast = result[indexLast]; if ((subLineLast.match(/\(/g) || []).length !== (subLineLast.match(/\)/g) || []).length) { const lastItem = `${result[indexLast]},${subLine}`; return [...result.slice(0, -1), lastItem]; } return [...result, subLine]; }, []); const isMultiple = layers.length > 1; // Calculate 'background-image' value const valueURL = layers.map(layer => { const hasURLValue = PATTERN_URL.test(layer); const valueGradient = layer.match(PATTERN_GRADIENT) ? layer.match(PATTERN_GRADIENT)[0] : null; if (hasURLValue) { return layer.replace(/(?:[^\s]+[\s]+)*(url\([^)]*\))(?:[\s]+[^\s]+)*/ig, '$1'); } if (valueGradient) { return layer.replace(/([^\s]+(?:[\s]+[^\s]+)*)/ig, valueGradient); } return layer.replace(/[^\s]+(?:[\s]+[^\s]+)*/ig, 'initial'); }).join(','); decl.cloneAfter({ prop: 'background-image', value: valueURL.trim() }); // Calculate 'background' value const valueRest = layers.map(layer => { const hasURLValue = PATTERN_URL.test(layer); if (!hasURLValue) { return layer; } return layer.replace(/([^\s]+[\s]+)*(?:url\([^)]*\)(?:[\s]+(?=[^\s]))?)([^\s]+[\s]*[^\s]+)*/ig, (match, group1, group2) => { const startPart = group1 || ''; const endPart = group2 || ''; const result = `${startPart}${endPart}`; if (isMultiple && !result.trim()) { return `${startPart}initial${endPart}`; } return result; }); }).join(','); if (!valueStartBgColor.trim() && !valueEndBgColor.trim() && !valueRest.replace(/(?:initial)|[\s,]+/ig, '')) { decl.remove(); } else { decl.replaceWith(decl.clone({ value: `${valueStartBgColor}${valueRest}${valueEndBgColor}`.trim() })); } } } }); } const PATTERN_URL$1 = /url\([^)]+\)[\s]*/i; /** * Checks value for containing of 'url()'. * * @param {string} value * * @returns {boolean} */ function hasValueUrl(value) { return PATTERN_URL$1.test(value); } const PATTERN_BACKGROUND_IMAGE = /background-image/i; /** * @param {string} css */ function cutter(css) { destructShorthand(css); css.walkDecls(PATTERN_BACKGROUND_IMAGE, decl => { if (hasValueUrl(decl.value) && !isNodeIgnored(decl)) { decl.remove(); } }); } const PATTERN_BACKGROUND_IMAGE$1 = /background-image/i; const IGNORING_AT_RULES_NAMES = ['charset', 'import', 'namespace']; /** * @param {string} css */ function cutterInvertor(css) { destructShorthand(css); css.walkDecls(decl => { if (isNodeIgnored(decl) || !hasValueUrl(decl.value) || !PATTERN_BACKGROUND_IMAGE$1.test(decl.prop)) { decl.remove(); } }); css.walkAtRules(rule => { if (IGNORING_AT_RULES_NAMES.indexOf(rule.name) !== -1) { rule.remove(); } }); } /** * @param {string} mode * * @returns {void} */ function getProcessor(mode) { switch (mode) { case 'cutter': return cutter; case 'cutterInvertor': return cutterInvertor; default: throw new Error(`Unknow mode for postcss-bgimage: ${mode}`); } } /** * @param {object} options - Plugin options. * * @returns {void} */ var index = postcss.plugin('postcss-bgimage', options => { if (!options) { throw new Error('Required params was not passed.'); } const { mode } = options; return css => getProcessor(mode)(css); }); module.exports = index; //# sourceMappingURL=index.js.map