You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.7 KiB

4 years ago
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _postcss = require('postcss');
  6. var _postcss2 = _interopRequireDefault(_postcss);
  7. var _postcssValueParser = require('postcss-value-parser');
  8. var _postcssValueParser2 = _interopRequireDefault(_postcssValueParser);
  9. var _svgo = require('svgo');
  10. var _svgo2 = _interopRequireDefault(_svgo);
  11. var _isSvg = require('is-svg');
  12. var _isSvg2 = _interopRequireDefault(_isSvg);
  13. var _url = require('./lib/url');
  14. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  15. const PLUGIN = 'postcss-svgo';
  16. const dataURI = /data:image\/svg\+xml(;((charset=)?utf-8|base64))?,/i;
  17. const dataURIBase64 = /data:image\/svg\+xml;base64,/i;
  18. function minifyPromise(decl, getSvgo, opts) {
  19. const promises = [];
  20. const parsed = (0, _postcssValueParser2.default)(decl.value);
  21. decl.value = parsed.walk(node => {
  22. if (node.type !== 'function' || node.value.toLowerCase() !== 'url' || !node.nodes.length) {
  23. return;
  24. }
  25. let { value, quote } = node.nodes[0];
  26. let isBase64, isUriEncoded;
  27. let svg = value.replace(dataURI, '');
  28. if (dataURIBase64.test(value)) {
  29. svg = Buffer.from(svg, 'base64').toString('utf8');
  30. isBase64 = true;
  31. } else {
  32. let decodedUri;
  33. try {
  34. decodedUri = (0, _url.decode)(svg);
  35. isUriEncoded = decodedUri !== svg;
  36. } catch (e) {
  37. // Swallow exception if we cannot decode the value
  38. isUriEncoded = false;
  39. }
  40. if (isUriEncoded) {
  41. svg = decodedUri;
  42. }
  43. if (opts.encode !== undefined) {
  44. isUriEncoded = opts.encode;
  45. }
  46. }
  47. if (!(0, _isSvg2.default)(svg)) {
  48. return;
  49. }
  50. promises.push(getSvgo().optimize(svg).then(result => {
  51. let data, optimizedValue;
  52. if (isBase64) {
  53. data = Buffer.from(result.data).toString('base64');
  54. optimizedValue = 'data:image/svg+xml;base64,' + data;
  55. } else {
  56. data = isUriEncoded ? (0, _url.encode)(result.data) : result.data;
  57. // Should always encode # otherwise we yield a broken SVG
  58. // in Firefox (works in Chrome however). See this issue:
  59. // https://github.com/cssnano/cssnano/issues/245
  60. data = data.replace(/#/g, '%23');
  61. optimizedValue = 'data:image/svg+xml;charset=utf-8,' + data;
  62. quote = isUriEncoded ? '"' : '\'';
  63. }
  64. node.nodes[0] = Object.assign({}, node.nodes[0], {
  65. value: optimizedValue,
  66. quote: quote,
  67. type: 'string',
  68. before: '',
  69. after: ''
  70. });
  71. }).catch(error => {
  72. throw new Error(`${PLUGIN}: ${error}`);
  73. }));
  74. return false;
  75. });
  76. return Promise.all(promises).then(() => decl.value = decl.value.toString());
  77. }
  78. exports.default = _postcss2.default.plugin(PLUGIN, (opts = {}) => {
  79. let svgo = null;
  80. const getSvgo = () => {
  81. if (!svgo) {
  82. svgo = new _svgo2.default(opts);
  83. }
  84. return svgo;
  85. };
  86. return css => {
  87. return new Promise((resolve, reject) => {
  88. const svgoQueue = [];
  89. css.walkDecls(decl => {
  90. if (!dataURI.test(decl.value)) {
  91. return;
  92. }
  93. svgoQueue.push(minifyPromise(decl, getSvgo, opts));
  94. });
  95. return Promise.all(svgoQueue).then(resolve, reject);
  96. });
  97. };
  98. });
  99. module.exports = exports['default'];