-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
css-versioning.es6.js
85 lines (75 loc) · 2.5 KB
/
css-versioning.es6.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
const { createHash } = require('node:crypto');
const { readdir, readFile, writeFile } = require('fs/promises');
const { existsSync, readFileSync } = require('node:fs');
const { dirname, extname, resolve } = require('node:path');
const { transform, composeVisitors } = require('lightningcss');
const { Timer } = require('./utils/timer.es6.js');
const skipExternal = true;
const variable = 'v';
function version(urlString, fromFile) {
// Skip external URLs
if (skipExternal && (urlString.startsWith('http') || urlString.startsWith('//'))) {
return `${urlString}`;
}
// Skip base64 URLs
if (urlString.startsWith('data:')) {
return `${urlString}`;
}
// Skip URLs with existing query
if (urlString.includes('?')) {
return `${urlString}`;
}
if (fromFile && existsSync(resolve(`${dirname(fromFile)}/${urlString}`))) {
const hash = createHash('md5');
hash.update(readFileSync(resolve(`${dirname(fromFile)}/${urlString}`)));
return `${urlString}?${variable}=${hash.digest('hex').substring(0, 6)}`;
}
return `${urlString}?${variable}=${(new Date()).valueOf().toString().substring(0, 6)}`;
}
/**
* @param {from: String} - the filepath for the css file
* @returns {import('lightningcss').Visitor} - A visitor that replaces the url
*/
function urlVersioning(fromFile) {
return {
/**
* @param {import('lightningcss').Url} url - The url object to transform
* @returns {import('lightningcss').Url} - The transformed url object
*/
Url(url) {
return { ...url, ...{ url: version(url.url, fromFile) } };
},
};
}
/**
* Adds a hash to the url() parts of the static css
*
* @param file
* @returns {Promise<void>}
*/
const fixVersion = async (file) => {
try {
const cssString = await readFile(file);
const { code } = transform({
code: cssString,
minify: false,
visitor: composeVisitors([urlVersioning(file)]),
});
await writeFile(file, code, { encoding: 'utf8', mode: 0o644 });
} catch (error) {
throw new Error(error);
}
};
/**
* Loop the media folder and add version to all url() entries in all the css files
*
* @returns {Promise<void>}
*/
module.exports.cssVersioning = async () => {
const bench = new Timer('Versioning');
const cssFiles = (await readdir('media', { withFileTypes: true, recursive: true }))
.filter((file) => (!file.isDirectory() && extname(file.name) === '.css'))
.map((file) => `${file.path}/${file.name}`);
Promise.all(cssFiles.map((file) => fixVersion(file)))
.then(() => bench.stop());
};