UNPKG

webpack-spritesmith

Version:

Webpack plugin that converts set of images into a spritesheet and SASS/LESS/Stylus mixins

174 lines (142 loc) 6.23 kB
"use strict"; function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } const _ = require('lodash'); const path = require('path'); const fs = require('fs'); const templater = require('spritesheet-templates'); const fThrowExpectField = f => { throw `Expected field "${f}" in options of SpritesmithPlugin`; }; module.exports = rawOptions => { rawOptions.src || fThrowExpectField('src'); rawOptions.src.cwd || fThrowExpectField('src.cwd'); rawOptions.src.glob || fThrowExpectField('src.glob'); rawOptions.target || fThrowExpectField('target'); rawOptions.target.css || fThrowExpectField('target.css'); rawOptions.target.image || fThrowExpectField('target.image'); const mergedOptions = _.merge({ src: { options: {} }, logCreatedFiles: false, apiOptions: { generateSpriteName: fileName => path.parse(path.relative(mergedOptions.src.cwd, fileName)).name, cssImageRef: rawOptions.target.image, customTemplates: {}, handlebarsHelpers: {} }, spritesmithOptions: {}, spritesheetTemplatesOptions: {} }, rawOptions); mergedOptions.target.css = normalizeTargetCss(mergedOptions); mergedOptions.target.css.forEach((css, i) => { if (!css[1].format) { throw 'SpritesmithPlugin was unable to derive ' + `css format from extension "${path.parse(css[0] || '').ext}" ` + `in "target.css[${i}]" and format was not specified explicitly`; } }); _.forEach(mergedOptions.customTemplates, (template, templateName) => { if (typeof template === 'string') { templater.addHandlebarsTemplate(templateName, fs.readFileSync(template, 'utf-8')); } else if (typeof template === 'function') { templater.addTemplate(templateName, template); } else { throw new Error('custom template can be either path/to/handlebars/template or actual template function'); } }); const handlebarsHelpers = mergedOptions.apiOptions.handlebarsHelpers; Object.keys(handlebarsHelpers).forEach(helperKey => { templater.registerHandlebarsHelper(helperKey, handlebarsHelpers[helperKey]); }); processRetinaOptions(mergedOptions); return mergedOptions; }; const normalizeTargetCss = mergedOptions => { let css = mergedOptions.target.css; if (!Array.isArray(css)) { css = [[css, mergedOptions.spritesheetTemplatesOptions]]; } return css.map((css, i) => { if (typeof css === 'string') { return [css, { format: extractFormatFromCSSFilename(css) }]; } if (Array.isArray(css)) { const _css$slice = css.slice(0), _css$slice2 = _slicedToArray(_css$slice, 2), cssFileName = _css$slice2[0], _css$slice2$ = _css$slice2[1], options = _css$slice2$ === void 0 ? {} : _css$slice2$; const format = options.format || extractFormatFromCSSFilename(cssFileName); return [cssFileName, _objectSpread({}, options, { format })]; } throw new Error(`'target.css[${i}] must be String or Array'`); }); }; const extensionToCssFormat = { '.stylus': 'stylus', '.styl': 'stylus', '.sass': 'sass', '.scss': 'scss', '.less': 'less', '.json': 'json', '.css': 'css' }; const extractFormatFromCSSFilename = cssFileName => extensionToCssFormat[path.parse(cssFileName).ext]; const processRetinaOptions = options => { if (!('retina' in options)) { return; } if (typeof options.retina === 'string') { const suffix = options.retina; const r = options.retina = { classifier: suffixToClassifier(suffix) }; r.targetImage = addSuffixToFileName(suffix, options.target.image, path); r.cssImageRef = addSuffixToFileName(suffix, options.apiOptions.cssImageRef, path.posix); } else { options.retina.classifier || fThrowExpectField('retina.classifier'); options.retina.targetImage || fThrowExpectField('retina.targetImage'); options.retina.cssImageRef || fThrowExpectField('retina.cssImageRef'); } options.target.css.forEach(css => { css[1].format += '_retina'; }); }; const suffixToClassifier = suffix => fileName => { const parsed = splitExt(fileName); if (endsWith(suffix, parsed.name)) { return { type: 'retina', retinaName: fileName, normalName: parsed.name.slice(0, -suffix.length) + parsed.ext }; } else { return { type: 'normal', retinaName: parsed.name + suffix + parsed.ext, normalName: fileName }; } }; const endsWith = (suffix, str) => str.slice(-suffix.length) === suffix; const splitExt = fileName => { const extInd = fileName.lastIndexOf('.'); return { name: fileName.slice(0, extInd), ext: fileName.slice(extInd) }; }; const addSuffixToFileName = (suffix, fileName, pathImpl) => { const parsed = pathImpl.parse(fileName); parsed.name += suffix; parsed.base = parsed.name + parsed.ext; return pathImpl.format(parsed); };