@zaininnari/postcss-cachebuster 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -4
- package/LICENSE +1 -0
- package/README.md +43 -31
- package/eslint.config.js +26 -0
- package/index.mjs +74 -17
- package/package.json +11 -2
- package/.eslintrc.json +0 -13
- package/.github/workflows/test-latest.yml +0 -31
- package/.github/workflows/test.yml +0 -28
- package/.idea/copilot.data.migration.ask2agent.xml +0 -6
- package/.idea/jsLibraryMappings.xml +0 -6
- package/.idea/misc.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 (2026-01-04)
|
|
4
|
+
|
|
5
|
+
- Add Prettier
|
|
6
|
+
|
|
7
|
+
## 0.4.1 (2026-01-02)
|
|
8
|
+
|
|
9
|
+
- Add ESLint
|
|
10
|
+
- @eslint/js recommended
|
|
11
|
+
- eslint-plugin-n recommended
|
|
12
|
+
|
|
3
13
|
## 0.4.0 (2025-12-30)
|
|
14
|
+
|
|
4
15
|
- update dependencies
|
|
5
16
|
- update support node version 20+
|
|
6
17
|
|
|
7
18
|
## 0.3.0 (2025-12-29)
|
|
19
|
+
|
|
8
20
|
- update npm package
|
|
9
21
|
- update support node version 18+
|
|
10
22
|
|
|
@@ -15,12 +27,13 @@
|
|
|
15
27
|
## 0.1.5 (2018-12-07)
|
|
16
28
|
|
|
17
29
|
## 0.1.4 (2017-01-07)
|
|
30
|
+
|
|
18
31
|
Fix multiple css imports in single css file.
|
|
19
32
|
|
|
20
33
|
## 0.1.3 (2016-05-27)
|
|
21
34
|
|
|
22
|
-
- `type` can be defined as function.
|
|
23
|
-
Thanks for Jackson Ray Hamilton [@jacksonrayhamilton](http://github.com/jacksonrayhamilton)
|
|
35
|
+
- `type` can be defined as function.
|
|
36
|
+
Thanks for Jackson Ray Hamilton [@jacksonrayhamilton](http://github.com/jacksonrayhamilton)
|
|
24
37
|
|
|
25
38
|
## 0.1.2 (2015-11-19)
|
|
26
39
|
|
|
@@ -29,5 +42,3 @@ Thanks for Jackson Ray Hamilton [@jacksonrayhamilton](http://github.com/jacksonr
|
|
|
29
42
|
## 0.1.1 (2015-11-18)
|
|
30
43
|
|
|
31
44
|
- Added .htc support
|
|
32
|
-
|
|
33
|
-
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
3
|
Copyright 2015 Gleb Mikheev <glebmachine@gmail.com>
|
|
4
|
+
Copyright 2026 zaininnari
|
|
4
5
|
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
7
|
this software and associated documentation files (the "Software"), to deal in
|
package/README.md
CHANGED
|
@@ -8,29 +8,34 @@ This project is a fork of https://github.com/glebmachine/postcss-cachebuster.
|
|
|
8
8
|
[PostCSS] plugin added cachebuster to local files based on their date changed.
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
|
+
|
|
11
12
|
```bash
|
|
12
13
|
npm i -D @zaininnari/postcss-cachebuster
|
|
13
14
|
```
|
|
14
15
|
|
|
15
16
|
## Usage
|
|
17
|
+
|
|
16
18
|
```js
|
|
17
19
|
import postcss from 'postcss';
|
|
18
20
|
import cachebuster from '@zaininnari/postcss-cachebuster';
|
|
19
21
|
|
|
20
|
-
await postcss([
|
|
22
|
+
const result = await postcss([
|
|
21
23
|
cachebuster({
|
|
22
24
|
imagesPath: '/images',
|
|
23
|
-
cssPath: '/stylesheets'
|
|
24
|
-
})
|
|
25
|
+
cssPath: '/stylesheets',
|
|
26
|
+
}),
|
|
25
27
|
]).process(css, { from: undefined });
|
|
28
|
+
|
|
29
|
+
result.css;
|
|
26
30
|
```
|
|
27
31
|
|
|
28
32
|
## Input css example
|
|
33
|
+
|
|
29
34
|
```css
|
|
30
|
-
@import url(
|
|
35
|
+
@import url('/css/styles.css');
|
|
31
36
|
.foo {
|
|
32
|
-
background-image
|
|
33
|
-
behavior
|
|
37
|
+
background-image: url('../images/index/logo.png');
|
|
38
|
+
behavior: url('../behaviors/backgroundsize.min.htc');
|
|
34
39
|
}
|
|
35
40
|
@font-face {
|
|
36
41
|
font-family: 'My font';
|
|
@@ -39,11 +44,12 @@ await postcss([
|
|
|
39
44
|
```
|
|
40
45
|
|
|
41
46
|
## Output css example
|
|
47
|
+
|
|
42
48
|
```css
|
|
43
|
-
@import url(
|
|
49
|
+
@import url('/css/styles.css?v66f22a33fff');
|
|
44
50
|
.foo {
|
|
45
|
-
background-image
|
|
46
|
-
behavior
|
|
51
|
+
background-image: url('../images/index/logo.png?v14f32a475b8');
|
|
52
|
+
behavior: url('../behaviors/backgroundsize.min.htc?v15f55a666c2');
|
|
47
53
|
}
|
|
48
54
|
@font-face {
|
|
49
55
|
font-family: 'My font';
|
|
@@ -52,14 +58,19 @@ await postcss([
|
|
|
52
58
|
```
|
|
53
59
|
|
|
54
60
|
## Configure
|
|
61
|
+
|
|
55
62
|
```js
|
|
56
|
-
postcss
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
import postcss from 'postcss';
|
|
64
|
+
import cachebuster from '@zaininnari/postcss-cachebuster';
|
|
65
|
+
|
|
66
|
+
postcss([
|
|
67
|
+
cachebuster({
|
|
68
|
+
imagesPath: '/images',
|
|
69
|
+
cssPath: '/stylesheets',
|
|
70
|
+
}),
|
|
71
|
+
]);
|
|
62
72
|
```
|
|
73
|
+
|
|
63
74
|
See [PostCSS] docs for examples for your environment.
|
|
64
75
|
|
|
65
76
|
[PostCSS]: https://postcss.org/
|
|
@@ -95,31 +106,32 @@ Add to this list by setting the `additionalProps` configuration option.
|
|
|
95
106
|
To add support for `mask-image` properties, for example:
|
|
96
107
|
|
|
97
108
|
```js
|
|
98
|
-
postcss
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
]
|
|
104
|
-
})
|
|
105
|
-
])
|
|
109
|
+
import postcss from 'postcss';
|
|
110
|
+
import cachebuster from '@zaininnari/postcss-cachebuster';
|
|
111
|
+
|
|
112
|
+
postcss([
|
|
113
|
+
cachebuster({
|
|
114
|
+
additionalProps: ['mask-image', '-webkit-mask-image'],
|
|
115
|
+
}),
|
|
116
|
+
]);
|
|
106
117
|
```
|
|
107
118
|
|
|
108
119
|
Replace the default list by setting the `supportedProps` configuration option.
|
|
109
120
|
To limit the cachbusting to background images only, for example:
|
|
110
121
|
|
|
111
122
|
```js
|
|
112
|
-
postcss
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
]
|
|
118
|
-
})
|
|
119
|
-
])
|
|
123
|
+
import postcss from 'postcss';
|
|
124
|
+
import cachebuster from '@zaininnari/postcss-cachebuster';
|
|
125
|
+
|
|
126
|
+
postcss([
|
|
127
|
+
cachebuster({
|
|
128
|
+
supportedProps: ['background', 'background-image'],
|
|
129
|
+
}),
|
|
130
|
+
]);
|
|
120
131
|
```
|
|
121
132
|
|
|
122
133
|
## Contributors
|
|
134
|
+
|
|
123
135
|
- Gleb Mikheev (https://github.com/glebmachine)
|
|
124
136
|
- Graham Bates (https://github.com/grahambates)
|
|
125
137
|
- Yusuke Yagyu (https://github.com/gyugyu)
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import n from 'eslint-plugin-n';
|
|
4
|
+
import eslintConfigPrettier from 'eslint-config-prettier';
|
|
5
|
+
import { defineConfig } from 'eslint/config';
|
|
6
|
+
|
|
7
|
+
export default defineConfig([
|
|
8
|
+
{
|
|
9
|
+
files: ['**/*.{js,mjs,cjs}'],
|
|
10
|
+
languageOptions: {
|
|
11
|
+
ecmaVersion: 'latest',
|
|
12
|
+
sourceType: 'module',
|
|
13
|
+
globals: {
|
|
14
|
+
...globals.node,
|
|
15
|
+
...globals.mocha,
|
|
16
|
+
myCustomGlobal: 'readonly',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
plugins: {
|
|
20
|
+
js,
|
|
21
|
+
n,
|
|
22
|
+
},
|
|
23
|
+
extends: ['js/recommended', 'n/recommended', eslintConfigPrettier],
|
|
24
|
+
ignores: ['eslint.config.js'],
|
|
25
|
+
},
|
|
26
|
+
]);
|
package/index.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import url from 'url';
|
|
2
1
|
import fs from 'fs';
|
|
3
2
|
import crypto from 'crypto';
|
|
4
3
|
import chalk from 'chalk';
|
|
@@ -7,8 +6,18 @@ import path from 'canonical-path';
|
|
|
7
6
|
|
|
8
7
|
const checksums = {};
|
|
9
8
|
|
|
9
|
+
/**
|
|
10
|
+
* parsed
|
|
11
|
+
* @typedef {Object} parsed
|
|
12
|
+
* @property {URL} u
|
|
13
|
+
* @property {boolean} isAbsolute
|
|
14
|
+
* @property {boolean} isRootRelativeButNotProtocolRelative
|
|
15
|
+
* @property {string} originalUrl
|
|
16
|
+
*/
|
|
17
|
+
|
|
10
18
|
const plugin = (opts = {}) => {
|
|
11
19
|
const pattern = /url\((['"])?([^'")]+)(['"])?\)/g;
|
|
20
|
+
// prettier-ignore
|
|
12
21
|
const supportedPropsDefault = [
|
|
13
22
|
'background',
|
|
14
23
|
'background-image',
|
|
@@ -42,9 +51,7 @@ const plugin = (opts = {}) => {
|
|
|
42
51
|
cachebuster = checksums[checksumKey];
|
|
43
52
|
} else {
|
|
44
53
|
const data = fs.readFileSync(assetPath);
|
|
45
|
-
cachebuster = crypto.createHash(opts.hashAlgorithm)
|
|
46
|
-
.update(data)
|
|
47
|
-
.digest('hex');
|
|
54
|
+
cachebuster = crypto.createHash(opts.hashAlgorithm).update(data).digest('hex');
|
|
48
55
|
|
|
49
56
|
checksums[checksumKey] = cachebuster;
|
|
50
57
|
}
|
|
@@ -56,10 +63,17 @@ const plugin = (opts = {}) => {
|
|
|
56
63
|
return cachebuster;
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
|
|
66
|
+
/**
|
|
67
|
+
* @param assetUrl {URL}
|
|
68
|
+
* @param file {string}
|
|
69
|
+
* @param imagesPath {string}
|
|
70
|
+
* @param isRootRelativeButNotProtocolRelative {boolean}
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
function resolveUrl(assetUrl, file, imagesPath, isRootRelativeButNotProtocolRelative) {
|
|
60
74
|
let assetPath = decodeURI(assetUrl.pathname);
|
|
61
75
|
|
|
62
|
-
if (
|
|
76
|
+
if (isRootRelativeButNotProtocolRelative) {
|
|
63
77
|
assetPath = path.join(imagesPath, assetPath);
|
|
64
78
|
} else {
|
|
65
79
|
assetPath = path.join(opts.cssPath || path.dirname(file), assetPath);
|
|
@@ -67,14 +81,22 @@ const plugin = (opts = {}) => {
|
|
|
67
81
|
return assetPath;
|
|
68
82
|
}
|
|
69
83
|
|
|
70
|
-
|
|
71
|
-
|
|
84
|
+
/**
|
|
85
|
+
* @param assetUrl {URL}
|
|
86
|
+
* @param inputFile {string}
|
|
87
|
+
* @param isRootRelativeButNotProtocolRelative {boolean}
|
|
88
|
+
*/
|
|
89
|
+
function updateAssetUrl(assetUrl, inputFile, isRootRelativeButNotProtocolRelative) {
|
|
90
|
+
const assetPath = resolveUrl(assetUrl, inputFile, opts.imagesPath, isRootRelativeButNotProtocolRelative);
|
|
72
91
|
|
|
73
92
|
// complete url with cachebuster
|
|
74
|
-
const
|
|
93
|
+
const originPath = isRootRelativeButNotProtocolRelative ? assetUrl.pathname : assetUrl.pathname.substring(1);
|
|
94
|
+
const cachebuster = createCachebuster(assetPath, originPath, opts.type);
|
|
75
95
|
if (!cachebuster) {
|
|
76
96
|
return;
|
|
77
|
-
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (typeof opts.type === 'function') {
|
|
78
100
|
assetUrl.pathname = cachebuster;
|
|
79
101
|
} else if (assetUrl.search && assetUrl.search.length > 1) {
|
|
80
102
|
assetUrl.search = assetUrl.search + '&' + opts.paramName + cachebuster;
|
|
@@ -83,6 +105,39 @@ const plugin = (opts = {}) => {
|
|
|
83
105
|
}
|
|
84
106
|
}
|
|
85
107
|
|
|
108
|
+
const DUMMY_BASE = 'http://localhost';
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param input {string}
|
|
112
|
+
* @returns {parsed}
|
|
113
|
+
*/
|
|
114
|
+
function parseUrlPreserveRelative(input) {
|
|
115
|
+
const isAbsolute = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(input);
|
|
116
|
+
const isRootRelativeButNotProtocolRelative = /^\/(?!\/)/.test(input);
|
|
117
|
+
const u = isAbsolute ? new URL(input) : new URL(input, DUMMY_BASE);
|
|
118
|
+
return { u, isAbsolute, isRootRelativeButNotProtocolRelative, originalUrl: input };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @param parsed {parsed}
|
|
123
|
+
* @returns {string|string}
|
|
124
|
+
*/
|
|
125
|
+
function formatUrlPreserveRelative(parsed) {
|
|
126
|
+
const u = parsed.u;
|
|
127
|
+
const isAbsolute = parsed.isAbsolute;
|
|
128
|
+
const isRootRelativeButNotProtocolRelative = parsed.isRootRelativeButNotProtocolRelative;
|
|
129
|
+
|
|
130
|
+
if (isAbsolute) {
|
|
131
|
+
return u.toString();
|
|
132
|
+
}
|
|
133
|
+
const url = `${u.pathname}${u.search}${u.hash}`;
|
|
134
|
+
if (!isRootRelativeButNotProtocolRelative) {
|
|
135
|
+
// remove start slash
|
|
136
|
+
return url.substring(1);
|
|
137
|
+
}
|
|
138
|
+
return url;
|
|
139
|
+
}
|
|
140
|
+
|
|
86
141
|
return {
|
|
87
142
|
postcssPlugin: 'postcss-cachebuster',
|
|
88
143
|
Once(root) {
|
|
@@ -96,10 +151,10 @@ const plugin = (opts = {}) => {
|
|
|
96
151
|
const quote = results[1] || '"';
|
|
97
152
|
const originalUrl = results[2];
|
|
98
153
|
|
|
99
|
-
const
|
|
100
|
-
updateAssetUrl(
|
|
154
|
+
const parsed = parseUrlPreserveRelative(originalUrl);
|
|
155
|
+
updateAssetUrl(parsed.u, inputFile, parsed.isRootRelativeButNotProtocolRelative, parsed.originalUrl);
|
|
101
156
|
|
|
102
|
-
atrule.params = 'url(' + quote +
|
|
157
|
+
atrule.params = 'url(' + quote + formatUrlPreserveRelative(parsed) + quote + ')';
|
|
103
158
|
});
|
|
104
159
|
|
|
105
160
|
root.walkDecls(function walkThroughtDeclarations(declaration) {
|
|
@@ -111,20 +166,22 @@ const plugin = (opts = {}) => {
|
|
|
111
166
|
declaration.value = declaration.value.replace(pattern, function (match, quote, originalUrl) {
|
|
112
167
|
quote = quote || '"';
|
|
113
168
|
|
|
114
|
-
const
|
|
169
|
+
const parsed = parseUrlPreserveRelative(originalUrl);
|
|
170
|
+
const assetUrl = parsed.u;
|
|
115
171
|
|
|
116
172
|
// only locals
|
|
117
173
|
if (
|
|
118
|
-
assetUrl.
|
|
174
|
+
assetUrl.toString().indexOf(DUMMY_BASE) !== 0 ||
|
|
175
|
+
parsed.isAbsolute ||
|
|
119
176
|
assetUrl.pathname.indexOf('//') === 0 ||
|
|
120
177
|
assetUrl.pathname.indexOf(';base64') !== -1
|
|
121
178
|
) {
|
|
122
179
|
return match;
|
|
123
180
|
}
|
|
124
181
|
|
|
125
|
-
updateAssetUrl(assetUrl, inputFile);
|
|
182
|
+
updateAssetUrl(assetUrl, inputFile, parsed.isRootRelativeButNotProtocolRelative);
|
|
126
183
|
|
|
127
|
-
return 'url(' + quote +
|
|
184
|
+
return 'url(' + quote + formatUrlPreserveRelative(parsed) + quote + ')';
|
|
128
185
|
});
|
|
129
186
|
});
|
|
130
187
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zaininnari/postcss-cachebuster",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Fork of postcss-cachebuster. Cachebusting all local files in css",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"postcss",
|
|
@@ -38,11 +38,17 @@
|
|
|
38
38
|
"path": "^0.12.7"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
+
"@eslint/js": "^9.39.2",
|
|
41
42
|
"chai": "^6.2.2",
|
|
43
|
+
"eslint": "^9.39.2",
|
|
44
|
+
"eslint-config-prettier": "^10.1.8",
|
|
45
|
+
"eslint-plugin-n": "^17.23.1",
|
|
46
|
+
"globals": "^16.5.0",
|
|
42
47
|
"gulp": "^5.0.1",
|
|
43
48
|
"gulp-mocha": "^10.0.1",
|
|
44
49
|
"gulp-postcss": "^10.0.0",
|
|
45
50
|
"postcss": "^8.5.6",
|
|
51
|
+
"prettier": "^3.7.4",
|
|
46
52
|
"sinon": "^21.0.1",
|
|
47
53
|
"sinon-chai": "^4.0.1"
|
|
48
54
|
},
|
|
@@ -50,6 +56,9 @@
|
|
|
50
56
|
"glob": "9.3.5"
|
|
51
57
|
},
|
|
52
58
|
"scripts": {
|
|
53
|
-
"
|
|
59
|
+
"lint": "eslint .",
|
|
60
|
+
"test": "gulp --gulpfile gulpfile.mjs",
|
|
61
|
+
"format:check": "prettier . --check",
|
|
62
|
+
"format:write": "prettier . --write"
|
|
54
63
|
}
|
|
55
64
|
}
|
package/.eslintrc.json
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Test (latest deps)
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
pull_request:
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
test:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
|
|
11
|
-
strategy:
|
|
12
|
-
matrix:
|
|
13
|
-
node-version: [20, 22, 24]
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v4
|
|
17
|
-
|
|
18
|
-
- name: Use Node.js
|
|
19
|
-
uses: actions/setup-node@v4
|
|
20
|
-
with:
|
|
21
|
-
node-version: ${{ matrix.node-version }}
|
|
22
|
-
|
|
23
|
-
- name: Remove package-lock.json
|
|
24
|
-
run: rm -f package-lock.json
|
|
25
|
-
|
|
26
|
-
- name: Install dependencies (latest allowed by package.json)
|
|
27
|
-
run: npm install
|
|
28
|
-
|
|
29
|
-
- name: Run tests
|
|
30
|
-
run: npm test
|
|
31
|
-
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
name: Test
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
pull_request:
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
test:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
|
|
11
|
-
strategy:
|
|
12
|
-
matrix:
|
|
13
|
-
node-version: [20, 22, 24]
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v4
|
|
17
|
-
|
|
18
|
-
- name: Use Node.js
|
|
19
|
-
uses: actions/setup-node@v4
|
|
20
|
-
with:
|
|
21
|
-
node-version: ${{ matrix.node-version }}
|
|
22
|
-
cache: 'npm'
|
|
23
|
-
|
|
24
|
-
- name: Install dependencies
|
|
25
|
-
run: npm ci
|
|
26
|
-
|
|
27
|
-
- name: Run tests
|
|
28
|
-
run: npm test
|
package/.idea/misc.xml
DELETED
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/postcss-cachebuster.iml" filepath="$PROJECT_DIR$/postcss-cachebuster.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|