Commit
+170 -2 +/-3 browse
1 | diff --git a/build/bundle-sizes.js b/build/bundle-sizes.js |
2 | new file mode 100644 |
3 | index 0000000..0e621d8 |
4 | --- /dev/null |
5 | +++ b/build/bundle-sizes.js |
6 | @@ -0,0 +1,92 @@ |
7 | + import path from 'node:path'; |
8 | + import postcss from 'postcss'; |
9 | + import fs from 'node:fs/promises'; |
10 | + import pkg from '../postcss.config.cjs'; |
11 | + import { createRequire } from 'node:module'; |
12 | + import { sync as brotli } from 'brotli-size'; |
13 | + import { gzipSizeSync as gzip } from 'gzip-size'; |
14 | + |
15 | + // Comes in handy later when we run postcss |
16 | + const { plugins } = pkg; |
17 | + |
18 | + // @ts-ignore |
19 | + const require = createRequire(import.meta.url); |
20 | + const { scripts } = require('../package.json'); |
21 | + /** |
22 | + * We build up an object with script:command pairs from package.json |
23 | + * |
24 | + * @type {Object.<string, string>} |
25 | + */ |
26 | + const filtered = Object.keys(scripts) |
27 | + .filter((key) => key.startsWith('lib:')) |
28 | + .reduce((obj, key) => { |
29 | + obj[key] = scripts[key]; |
30 | + return obj; |
31 | + }, {}); |
32 | + |
33 | + /** |
34 | + * The regex captures a filepath and filename group from an npm command. |
35 | + * |
36 | + * Captures for the command `postcss src/extra/normalize.light.css -o normalize.light.min.css` yields |
37 | + * { |
38 | + * groups: { |
39 | + * filepath: 'src/extra/normalize.light.css', |
40 | + * filename: 'normalize.light.min.css' |
41 | + * } |
42 | + * } |
43 | + */ |
44 | + const regex = /postcss\s(?<filepath>\S+)\s\-[o]\s(?<filename>.*\.css)(?:.*$)/; |
45 | + |
46 | + /** |
47 | + * @typedef {Object} Size |
48 | + * @propety {number} raw - Unminified size in bytes |
49 | + * @property {string} size - Unminified size in KiB |
50 | + * @property {string} minified - Minified size in KiB |
51 | + * @property {string} brotli - Brotli compressed minified size in KiB |
52 | + * @property {string} gzip - Gzip compressed minified size in KiB |
53 | + */ |
54 | + /** @type {Object.<string, Size>} sizes */ |
55 | + let sizes = {} |
56 | + |
57 | + for (const [_, script] of Object.entries(filtered)) { |
58 | + const found = script.match(regex); |
59 | + |
60 | + if (!found) continue; |
61 | + |
62 | + /** |
63 | + * @typedef {object} CaptureGroup |
64 | + * @property {string} filepath |
65 | + * @property {string} filename |
66 | + */ |
67 | + /** @type {CaptureGroup} */ |
68 | + const { filepath, filename } = found.groups; |
69 | + |
70 | + /** |
71 | + * @type {import('postcss').ProcessOptions} |
72 | + */ |
73 | + const options = { from: path.resolve(`../${filepath}`), to: undefined }; |
74 | + const css = await fs.readFile(path.resolve(`../${filepath}`), 'utf-8'); |
75 | + /** |
76 | + * Run the css through PostCSS (just like Open-Props). |
77 | + * plugins.slice(0, -1) remove `cssnano` plugin so we can get the size of the unminified code |
78 | + */ |
79 | + const code = await postcss(plugins.slice(0, -1)).process(css, options); |
80 | + /** |
81 | + * This time we want to get the minified size. |
82 | + */ |
83 | + const minified = await postcss(plugins).process(css, options); |
84 | + |
85 | + /** |
86 | + * Build the sizes object. |
87 | + * Strip `.min` from the filename |
88 | + */ |
89 | + sizes[filename.replace('.min', '')] = { |
90 | + raw: code.css.length, // in bytes |
91 | + size: (code.css.length / 1024).toFixed(2), // in KiB |
92 | + minified: (minified.css.length / 1024).toFixed(2), // KiB |
93 | + brotli: (brotli(minified.css) / 1024).toFixed(2), // in KiB |
94 | + gzip: (gzip(minified.css) / 1024).toFixed(2), // in KiB |
95 | + } |
96 | + } |
97 | + |
98 | + await fs.writeFile('bundle-sizes.json', JSON.stringify(sizes, null, 2), { encoding: 'utf8' }); |
99 | diff --git a/package-lock.json b/package-lock.json |
100 | index 1efa6ab..02ffb78 100644 |
101 | --- a/package-lock.json |
102 | +++ b/package-lock.json |
103 | @@ -1,18 +1,20 @@ |
104 | { |
105 | "name": "open-props", |
106 | - "version": "1.6.8", |
107 | + "version": "1.6.19", |
108 | "lockfileVersion": 2, |
109 | "requires": true, |
110 | "packages": { |
111 | "": { |
112 | "name": "open-props", |
113 | - "version": "1.6.8", |
114 | + "version": "1.6.19", |
115 | "license": "MIT", |
116 | "devDependencies": { |
117 | "ava": "^3.15.0", |
118 | + "brotli-size": "^4.0.0", |
119 | "colorjs.io": "^0.4.1-patch.1", |
120 | "concurrently": "^7.2.2", |
121 | "cssnano": "^5.1.10", |
122 | + "gzip-size": "^7.0.0", |
123 | "json": "^11.0.0", |
124 | "open-color": "^1.9.1", |
125 | "postcss": "^8.3.9", |
126 | @@ -695,6 +697,18 @@ |
127 | "node": ">=8" |
128 | } |
129 | }, |
130 | + "node_modules/brotli-size": { |
131 | + "version": "4.0.0", |
132 | + "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-4.0.0.tgz", |
133 | + "integrity": "sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==", |
134 | + "dev": true, |
135 | + "dependencies": { |
136 | + "duplexer": "0.1.1" |
137 | + }, |
138 | + "engines": { |
139 | + "node": ">= 10.16.0" |
140 | + } |
141 | + }, |
142 | "node_modules/browserslist": { |
143 | "version": "4.20.3", |
144 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", |
145 | @@ -1766,6 +1780,12 @@ |
146 | "node": ">=8" |
147 | } |
148 | }, |
149 | + "node_modules/duplexer": { |
150 | + "version": "0.1.1", |
151 | + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", |
152 | + "integrity": "sha512-sxNZ+ljy+RA1maXoUReeqBBpBC6RLKmg5ewzV+x+mSETmWNoKdZN6vcQjpFROemza23hGFskJtFNoUWUaQ+R4Q==", |
153 | + "dev": true |
154 | + }, |
155 | "node_modules/duplexer3": { |
156 | "version": "0.1.4", |
157 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", |
158 | @@ -2113,6 +2133,27 @@ |
159 | "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", |
160 | "dev": true |
161 | }, |
162 | + "node_modules/gzip-size": { |
163 | + "version": "7.0.0", |
164 | + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz", |
165 | + "integrity": "sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==", |
166 | + "dev": true, |
167 | + "dependencies": { |
168 | + "duplexer": "^0.1.2" |
169 | + }, |
170 | + "engines": { |
171 | + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
172 | + }, |
173 | + "funding": { |
174 | + "url": "https://github.com/sponsors/sindresorhus" |
175 | + } |
176 | + }, |
177 | + "node_modules/gzip-size/node_modules/duplexer": { |
178 | + "version": "0.1.2", |
179 | + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", |
180 | + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", |
181 | + "dev": true |
182 | + }, |
183 | "node_modules/has": { |
184 | "version": "1.0.3", |
185 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", |
186 | @@ -6810,6 +6851,15 @@ |
187 | "fill-range": "^7.0.1" |
188 | } |
189 | }, |
190 | + "brotli-size": { |
191 | + "version": "4.0.0", |
192 | + "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-4.0.0.tgz", |
193 | + "integrity": "sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==", |
194 | + "dev": true, |
195 | + "requires": { |
196 | + "duplexer": "0.1.1" |
197 | + } |
198 | + }, |
199 | "browserslist": { |
200 | "version": "4.20.3", |
201 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", |
202 | @@ -7581,6 +7631,12 @@ |
203 | "is-obj": "^2.0.0" |
204 | } |
205 | }, |
206 | + "duplexer": { |
207 | + "version": "0.1.1", |
208 | + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", |
209 | + "integrity": "sha512-sxNZ+ljy+RA1maXoUReeqBBpBC6RLKmg5ewzV+x+mSETmWNoKdZN6vcQjpFROemza23hGFskJtFNoUWUaQ+R4Q==", |
210 | + "dev": true |
211 | + }, |
212 | "duplexer3": { |
213 | "version": "0.1.4", |
214 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", |
215 | @@ -7841,6 +7897,23 @@ |
216 | "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", |
217 | "dev": true |
218 | }, |
219 | + "gzip-size": { |
220 | + "version": "7.0.0", |
221 | + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz", |
222 | + "integrity": "sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==", |
223 | + "dev": true, |
224 | + "requires": { |
225 | + "duplexer": "^0.1.2" |
226 | + }, |
227 | + "dependencies": { |
228 | + "duplexer": { |
229 | + "version": "0.1.2", |
230 | + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", |
231 | + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", |
232 | + "dev": true |
233 | + } |
234 | + } |
235 | + }, |
236 | "has": { |
237 | "version": "1.0.3", |
238 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", |
239 | diff --git a/package.json b/package.json |
240 | index 7490fe8..8d50179 100644 |
241 | --- a/package.json |
242 | +++ b/package.json |
243 | @@ -186,6 +186,7 @@ |
244 | "build": "concurrently npm:gen:op npm:gen:shadowdom && npm run gen:types", |
245 | "test": "ava test/basic.test.cjs", |
246 | "bundle": "concurrently npm:lib:* -m 25 && concurrently npm:shadow:* -m 25", |
247 | + "bundle:sizes": "cd build && node bundle-sizes.js", |
248 | "gen:op": "cd build && node props.js \"\" true", |
249 | "gen:nowhere": "cd build && node props \"\" false", |
250 | "gen:shadowdom": "cd build && node props \"\" false \":host\" \"shadow\"", |
251 | @@ -313,9 +314,11 @@ |
252 | }, |
253 | "devDependencies": { |
254 | "ava": "^3.15.0", |
255 | + "brotli-size": "^4.0.0", |
256 | "colorjs.io": "^0.4.1-patch.1", |
257 | "concurrently": "^7.2.2", |
258 | "cssnano": "^5.1.10", |
259 | + "gzip-size": "^7.0.0", |
260 | "json": "^11.0.0", |
261 | "open-color": "^1.9.1", |
262 | "postcss": "^8.3.9", |