UNPKG

2.91 kBJavaScriptView Raw
1import path from 'node:path';
2import postcss from 'postcss';
3import fs from 'node:fs/promises';
4import pkg from '../postcss.config.cjs';
5import { createRequire } from 'node:module';
6import { sync as brotli } from 'brotli-size';
7import { gzipSizeSync as gzip } from 'gzip-size';
8
9// Comes in handy later when we run postcss
10const { plugins } = pkg;
11
12// @ts-ignore
13const require = createRequire(import.meta.url);
14const { scripts } = require('../package.json');
15/**
16 * We build up an object with script:command pairs from package.json
17 *
18 * @type {Object.<string, string>}
19 */
20const filtered = Object.keys(scripts)
21 .filter((key) => key.startsWith('lib:'))
22 .reduce((obj, key) => {
23 obj[key] = scripts[key];
24 return obj;
25 }, {});
26
27/**
28 * The regex captures a filepath and filename group from an npm command.
29 *
30 * Captures for the command `postcss src/extra/normalize.light.css -o normalize.light.min.css` yields
31 * {
32 * groups: {
33 * filepath: 'src/extra/normalize.light.css',
34 * filename: 'normalize.light.min.css'
35 * }
36 * }
37 */
38const regex = /postcss\s(?<filepath>\S+)\s\-[o]\s(?<filename>.*\.css)(?:.*$)/;
39
40/**
41 * @typedef {Object} Size
42 * @property {number} raw - Unminified size in bytes
43 * @property {string} size - Unminified size in KiB
44 * @property {string} minified - Minified size in KiB
45 * @property {string} brotli - Brotli compressed minified size in KiB
46 * @property {string} gzip - Gzip compressed minified size in KiB
47 */
48 /** @type {Object.<string, Size>} sizes */
49let sizes = {}
50
51for (const [_, script] of Object.entries(filtered)) {
52 const found = script.match(regex);
53
54 if (!found) continue;
55
56 /**
57 * @typedef {object} CaptureGroup
58 * @property {string} filepath
59 * @property {string} filename
60 */
61 /** @type {CaptureGroup} */
62 const { filepath, filename } = found.groups;
63
64 /**
65 * @type {import('postcss').ProcessOptions}
66 */
67 const options = { from: path.resolve(`../${filepath}`), to: undefined };
68 const css = await fs.readFile(path.resolve(`../${filepath}`), 'utf-8');
69 /**
70 * Run the css through PostCSS (just like Open-Props).
71 * plugins.slice(0, -1) remove `cssnano` plugin so we can get the size of the unminified code
72 */
73 const code = await postcss(plugins.slice(0, -1)).process(css, options);
74 /**
75 * This time we want to get the minified size.
76 */
77 const minified = await postcss(plugins).process(css, options);
78
79 /**
80 * Build the sizes object.
81 * Strip `.min` from the filename
82 */
83 sizes[filename.replace('.min', '')] = {
84 raw: code.css.length, // in bytes
85 size: (code.css.length / 1024).toFixed(2), // in KiB
86 minified: (minified.css.length / 1024).toFixed(2), // KiB
87 brotli: (brotli(minified.css) / 1024).toFixed(2), // in KiB
88 gzip: (gzip(minified.css) / 1024).toFixed(2), // in KiB
89 }
90}
91
92await fs.writeFile('bundle-sizes.json', JSON.stringify(sizes, null, 2), { encoding: 'utf8' });