forked from phlppschrr/gulp-compass-imagehelper
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.js
150 lines (129 loc) · 4.47 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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
const fs = require('fs');
const path = require('canonical-path');
const log = require('fancy-log');
const colors = require('ansi-colors');
const Vinyl = require('vinyl');
const Through = require('through');
const mustache = require('mustache');
const sizeOf = require('image-size');
const mime = require('mime');
const md5 = require('md5');
const { optimize } = require('svgo');
const appRoot = require('app-root-path').path;
let images = [];
let options = {
template: path.join(__dirname, 'sass-image-template.mustache'),
targetFile: '_sass-image.scss',
prefix: '',
};
function pathPrefix() {
let result = '';
if (options.http_images_path) {
result = options.http_images_path;
} else if (options.css_path && options.images_path) {
// Relative path from css folder to images
result = path.relative(options.css_path, options.images_path);
} else if (options.images_path) {
// Relative from project url
result = path.relative(appRoot, options.images_path);
}
// Make sure pathPrefix ends with a trailing slash
if (result && result.substring(-1) !== '/') {
result = `${result}/`;
}
return result;
}
function isSet(val) {
return typeof val !== 'undefined' && val !== null;
}
function getSvgDimensions(file) {
let dimensions = {
width: undefined,
height: undefined,
};
try {
dimensions = sizeOf(file.path);
} catch (e) {
// Could not read width/height from svg. Try again with the slower svgo parser:
optimize(file.contents.toString(), (res) => {
// Check if dimensions could be read, log notice if not
if (!isSet(res) || !isSet(res.info) || !isSet(res.info.width) || !isSet(res.info.height)) {
const filePath = path.relative(options.images_path, file.path);
log(
colors.yellow('NOTICE'),
'Image Dimensions could not be determined for:',
colors.cyan(filePath)
);
return;
}
dimensions = {
width: res.info.width,
height: res.info.height,
};
});
}
return dimensions;
}
function bufferContents(file) {
if (!options.images_path) {
// Autodetect images_path with the first file
options.images_path = path.relative(appRoot, file.base);
}
const imageInfo = {};
let encoding = 'base64';
let data;
const mimetype = mime.getType(file.path);
let dimensions;
if (mimetype === 'image/svg+xml') {
dimensions = getSvgDimensions(file);
encoding = 'charset=utf8';
data = file.contents.toString('utf8');
data = data.replace(/'/g, '"');
data = data.replace(/\s+/g, ' ');
data = data.replace(
/[\(\){}\|\\\^~\[\]`"<>#%]/g,
(match) => `%${match[0].charCodeAt(0).toString(16).toUpperCase()}`
);
} else {
dimensions = sizeOf(file.path);
data = file.contents.toString(encoding);
}
imageInfo.width = dimensions.width;
imageInfo.height = dimensions.height;
imageInfo.mime = mimetype;
imageInfo.filename = path.basename(file.path);
imageInfo.basename = path.basename(file.path, path.extname(file.path));
imageInfo.dirname = path.basename(path.dirname(file.path));
imageInfo.ext = path.extname(file.path);
imageInfo.path = path.relative(options.images_path, file.path);
// Replace /, \, . and @ with -
imageInfo.fullname = imageInfo.path.replace(/[\/\\\.@]/g, '-');
imageInfo.hash = md5(file.contents);
imageInfo.data = `url("data:${mimetype};${encoding},${data}")`;
images.push(imageInfo);
}
function endStream() {
const template = fs.readFileSync(options.template).toString();
this.emit('data', new Vinyl({
contents: Buffer.from(mustache.render(template, {
prefix: options.prefix,
path_prefix: pathPrefix(),
items: images,
includeData: options.includeData,
createPlaceholder: options.createPlaceholder,
}), 'utf8'),
path: options.targetFile,
}));
this.emit('end');
}
module.exports = (opts = {}) => {
images = [];
options = Object.assign(options, opts);
if (options.includeData !== false) {
options.includeData = true;
}
if (options.createPlaceholder !== false) {
options.createPlaceholder = true;
}
return new Through(bufferContents, endStream);
};