/
index.js
110 lines (93 loc) · 2.7 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import valueParser from 'postcss-value-parser';
import { optimize } from 'svgo';
import { encode, decode } from './lib/url';
const PLUGIN = 'postcss-svgo';
const dataURI = /data:image\/svg\+xml(;((charset=)?utf-8|base64))?,/i;
const dataURIBase64 = /data:image\/svg\+xml;base64,/i;
function minify(decl, opts, postcssResult) {
const parsed = valueParser(decl.value);
decl.value = parsed.walk((node) => {
if (
node.type !== 'function' ||
node.value.toLowerCase() !== 'url' ||
!node.nodes.length
) {
return;
}
let { value, quote } = node.nodes[0];
let isBase64, isUriEncoded;
const url = new URL(value);
let svg = value.replace(dataURI, '');
if (dataURIBase64.test(value)) {
let base64String = `${url.protocol}${url.pathname}`.replace(dataURI, '');
svg = Buffer.from(base64String, 'base64').toString('utf8');
isBase64 = true;
} else {
if (!dataURI.test(value)) {
return;
}
let decodedUri;
try {
decodedUri = decode(svg);
isUriEncoded = decodedUri !== svg;
} catch (e) {
// Swallow exception if we cannot decode the value
isUriEncoded = false;
}
if (isUriEncoded) {
svg = decodedUri;
}
if (opts.encode !== undefined) {
isUriEncoded = opts.encode;
}
}
let result;
try {
result = optimize(svg, opts);
if (result.error) {
decl.warn(postcssResult, `${result.error}`);
return;
}
} catch (error) {
decl.warn(postcssResult, `${error}`);
return;
}
let data, optimizedValue;
if (isBase64) {
data = Buffer.from(result.data).toString('base64');
optimizedValue = 'data:image/svg+xml;base64,' + data + url.hash;
} else {
data = isUriEncoded ? encode(result.data) : result.data;
// Should always encode # otherwise we yield a broken SVG
// in Firefox (works in Chrome however). See this issue:
// https://github.com/cssnano/cssnano/issues/245
data = data.replace(/#/g, '%23');
optimizedValue = 'data:image/svg+xml;charset=utf-8,' + data;
quote = isUriEncoded ? '"' : "'";
}
node.nodes[0] = Object.assign({}, node.nodes[0], {
value: optimizedValue,
quote: quote,
type: 'string',
before: '',
after: '',
});
return false;
});
decl.value = decl.value.toString();
}
function pluginCreator(opts = {}) {
return {
postcssPlugin: PLUGIN,
OnceExit(css, { result }) {
css.walkDecls((decl) => {
if (!dataURI.test(decl.value)) {
return;
}
minify(decl, opts, result);
});
},
};
}
pluginCreator.postcss = true;
export default pluginCreator;