compress-shader-literals 0.0.4 → 0.0.7
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/README.md +57 -46
- package/dist/index.d.ts +41 -0
- package/dist/index.js +15 -32
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -1,15 +1,44 @@
|
|
|
1
1
|
# compress-shader-literals
|
|
2
2
|
|
|
3
|
-
> **Size matters.**
|
|
3
|
+
> **Size matters.** Strip everything strippable from your GLSL & WGSL shaders at build time.
|
|
4
|
+
|
|
5
|
+
> ⭐ Star this repository to support development and help others discover it.
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/compress-shader-literals)
|
|
6
8
|
[](https://bundlephobia.com/package/compress-shader-literals)
|
|
7
9
|
[](https://www.npmjs.com/package/compress-shader-literals)
|
|
8
10
|
[](./LICENSE)
|
|
9
11
|
|
|
10
|
-
Your shaders ship
|
|
12
|
+
Your shaders ship to users as strings. This strips the comments and whitespace out of them at build time, before your bundler ever sees them — in any bundler.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
## Stats
|
|
17
|
+
|
|
18
|
+
Measured on the real shaders shipped by popular libraries:
|
|
19
|
+
|
|
20
|
+
<!-- STATS:START -->
|
|
21
|
+
|
|
22
|
+
| Package | Shaders | Before | After | Saved |
|
|
23
|
+
| --------------------- | ------: | --------: | --------: | --------: |
|
|
24
|
+
| `three` | 281 | 240,772 B | 203,428 B | **15.5%** |
|
|
25
|
+
| `@jayf0x/fluidity-js` | 9 | 9,524 B | 7,133 B | **25.1%** |
|
|
26
|
+
| `ogl` | 22 | 6,109 B | 5,335 B | **12.7%** |
|
|
27
|
+
| `shader-park-core` | 18 | 10,794 B | 9,033 B | **16.3%** |
|
|
28
|
+
| `curtainsjs` | 7 | 3,406 B | 2,563 B | **24.8%** |
|
|
29
|
+
| **Total** | 337 | 270,605 B | 227,492 B | **15.9%** |
|
|
30
|
+
|
|
31
|
+
_Auto-generated by [`tests/e2e.js`](tests/e2e.js) · packages [verified](tests/validate.js) loadable · 2026-06-24_
|
|
32
|
+
|
|
33
|
+
<!-- STATS:END -->
|
|
11
34
|
|
|
12
|
-
|
|
35
|
+
<!-- <a href="https://star-history.com/#jayf0x/compress-shader-literals&Date">
|
|
36
|
+
<picture>
|
|
37
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=jayf0x/compress-shader-literals&type=Date&theme=dark&legend=top-left" />
|
|
38
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=jayf0x/compress-shader-literals&type=Date&legend=top-left" />
|
|
39
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=jayf0x/compress-shader-literals&type=Date&legend=top-left" />
|
|
40
|
+
</picture>
|
|
41
|
+
</a> -->
|
|
13
42
|
|
|
14
43
|
## Install
|
|
15
44
|
|
|
@@ -34,74 +63,56 @@ export default { plugins: [compressShaderLiterals.vite({ outputRatio: true })] }
|
|
|
34
63
|
// Rspack / Rolldown / Farm → .rspack() / .rolldown() / .farm()
|
|
35
64
|
```
|
|
36
65
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
## What it compresses
|
|
66
|
+
It finds tagged and comment-prefixed literals — and yes, the comment form keeps your editor's syntax highlighting:
|
|
40
67
|
|
|
41
68
|
```ts
|
|
42
|
-
// Tagged template literal
|
|
43
69
|
const vert = glsl`
|
|
44
70
|
// vertex shader ← stripped
|
|
45
71
|
precision highp float;
|
|
46
72
|
void main() { gl_Position = vec4(0.0); }
|
|
47
73
|
`;
|
|
48
74
|
|
|
49
|
-
// Comment-prefixed template literal (great for editor syntax highlighting)
|
|
50
75
|
const frag = /* wgsl */ `
|
|
51
76
|
/* fragment */
|
|
52
77
|
fn main() {}
|
|
53
78
|
`;
|
|
54
79
|
```
|
|
55
80
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
## Options
|
|
59
|
-
|
|
60
|
-
| Option | Default | Description |
|
|
61
|
-
| ------------- | ---------------------------- | --------------------------------------- |
|
|
62
|
-
| `tags` | `['glsl', 'wgsl', 'shader']` | Tag names / comment markers to match |
|
|
63
|
-
| `include` | `[/\.[jt]sx?$/]` | Files to process |
|
|
64
|
-
| `exclude` | `[/node_modules/, /dist/]` | Files to skip |
|
|
65
|
-
| `outputRatio` | `false` | Print a bytes-saved summary after build |
|
|
66
|
-
|
|
67
|
-
With `outputRatio: true`:
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
compress-shader-literals
|
|
71
|
-
────────────────────────
|
|
72
|
-
215.00 B → 134.00 B
|
|
73
|
-
saved: 81.00 B (37.67% smaller)
|
|
74
|
-
shaders: 1
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Real-world stats
|
|
81
|
+
Both collapse to a single tight line. No comments, no padding, no touched source files.
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
**Options**
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
| Option | Default | Description |
|
|
86
|
+
| ------------- | ---------------------------- | -------------------------------------------------- |
|
|
87
|
+
| `tags` | `['glsl', 'wgsl', 'shader']` | Tag names / comment markers to match |
|
|
88
|
+
| `include` | `[/\.[jt]sx?$/]` | Files to process |
|
|
89
|
+
| `exclude` | `[/node_modules/, /dist/]` | Files to skip |
|
|
90
|
+
| `outputRatio` | `false` | Print a bytes-saved summary after build |
|
|
91
|
+
| `transform` | built-in `minifyShader` | Custom minifier — `(shader: string) => string` |
|
|
92
|
+
| `debug` | `false` | Log each file's discovered literals to the console |
|
|
82
93
|
|
|
83
|
-
|
|
84
|
-
| --------------------- | ------: | --------: | --------: | --------: |
|
|
85
|
-
| `three` | 281 | 240,772 B | 203,428 B | **15.5%** |
|
|
86
|
-
| `@jayf0x/fluidity-js` | 9 | 9,524 B | 7,133 B | **25.1%** |
|
|
87
|
-
| `ogl` | 22 | 6,109 B | 5,335 B | **12.7%** |
|
|
88
|
-
| `shader-park-core` | 18 | 10,794 B | 9,033 B | **16.3%** |
|
|
89
|
-
| `curtainsjs` | 7 | 3,406 B | 2,563 B | **24.8%** |
|
|
90
|
-
| **Total** | 337 | 270,605 B | 227,492 B | **15.9%** |
|
|
94
|
+
**Programmatic API** — the two core helpers are exported for tooling authors (validators, ESLint rules, CLIs), no plugin required:
|
|
91
95
|
|
|
92
|
-
|
|
96
|
+
```js
|
|
97
|
+
import { extractShaderLiterals, minifyShader } from 'compress-shader-literals';
|
|
93
98
|
|
|
94
|
-
|
|
99
|
+
extractShaderLiterals('const v = glsl`void main() {}`');
|
|
100
|
+
// → [{ tag: 'glsl', value: 'void main() {}', start: 10, end: 26 }]
|
|
95
101
|
|
|
96
|
-
|
|
102
|
+
minifyShader('// comment\nvoid main() {}'); // → 'void main() {}'
|
|
103
|
+
```
|
|
97
104
|
|
|
98
105
|
## How it works
|
|
99
106
|
|
|
107
|
+
Nothing clever, which is the point:
|
|
108
|
+
|
|
100
109
|
1. Parses each matched file with Babel (TS/JSX aware).
|
|
101
|
-
2. Finds tagged and comment-prefixed shader literals
|
|
102
|
-
3. Strips comments + collapses whitespace
|
|
110
|
+
2. Finds tagged and comment-prefixed shader literals.
|
|
111
|
+
3. Strips comments + collapses whitespace via [`magic-string`](https://github.com/Rich-Harris/magic-string), so **sourcemaps stay intact**.
|
|
103
112
|
4. Runs as a `pre` transform, so your bundler's own minifier still sees the result.
|
|
104
113
|
|
|
114
|
+
One [unplugin](https://github.com/unjs/unplugin) covers **Vite, Rollup, webpack, esbuild, Rspack, Rolldown & Farm**.
|
|
115
|
+
|
|
105
116
|
## License
|
|
106
117
|
|
|
107
|
-
[MIT](./LICENSE) © jayF0x
|
|
118
|
+
[MIT](./LICENSE) © [jayF0x](https://github.com/jayf0x)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { UnpluginInstance } from 'unplugin';
|
|
2
|
+
|
|
3
|
+
/** A picomatch glob string, RegExp, or a list of them — matched against module ids. */
|
|
4
|
+
type FilterPattern = string | RegExp | ReadonlyArray<string | RegExp> | null;
|
|
5
|
+
|
|
6
|
+
export interface CompressShaderLiteralsOptions {
|
|
7
|
+
/** Tag names / comment markers to match. Default: `['glsl', 'wgsl', 'shader']` */
|
|
8
|
+
tags?: string[];
|
|
9
|
+
/** Files to process. Default: `[/\.[jt]sx?$/]` */
|
|
10
|
+
include?: FilterPattern;
|
|
11
|
+
/** Files to skip. Default: `[/node_modules/, /dist/]` */
|
|
12
|
+
exclude?: FilterPattern;
|
|
13
|
+
/** Print a bytes-saved summary after build. Default: `false` */
|
|
14
|
+
outputRatio?: boolean;
|
|
15
|
+
/** Custom minifier, replaces the built-in `minifyShader`. Receives the raw literal, returns the transformed source. */
|
|
16
|
+
transform?: (shader: string) => string;
|
|
17
|
+
/** Log each file's discovered literals to the console. Default: `false` */
|
|
18
|
+
debug?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A shader literal discovered in source. */
|
|
22
|
+
export interface ShaderLiteral {
|
|
23
|
+
tag: string;
|
|
24
|
+
value: string;
|
|
25
|
+
start: number;
|
|
26
|
+
end: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Minify GLSL/WGSL shader template literals at build time.
|
|
31
|
+
*
|
|
32
|
+
* Universal plugin — call the bundler you use: `.vite()`, `.rollup()`,
|
|
33
|
+
* `.webpack()`, `.esbuild()`, `.rspack()`, `.rolldown()`, `.farm()`.
|
|
34
|
+
*/
|
|
35
|
+
export declare const compressShaderLiterals: UnpluginInstance<CompressShaderLiteralsOptions | undefined, boolean>;
|
|
36
|
+
|
|
37
|
+
/** Find tagged (`glsl\`...\``) and comment-prefixed (`/* wgsl *\/ \`...\``) shader literals in source. */
|
|
38
|
+
export declare function extractShaderLiterals(code: string, tags?: string[]): ShaderLiteral[];
|
|
39
|
+
|
|
40
|
+
/** Strip comments and collapse whitespace in a shader source string. */
|
|
41
|
+
export declare function minifyShader(src: string): string;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/plugin.js
|
|
2
2
|
import { createFilter } from "@rollup/pluginutils";
|
|
3
|
+
import { diff, snap } from "byte-snap";
|
|
3
4
|
import MagicString from "magic-string";
|
|
4
5
|
import { createUnplugin } from "unplugin";
|
|
5
6
|
|
|
@@ -62,31 +63,12 @@ function minifyShader(src) {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
// src/plugin.js
|
|
65
|
-
function fmtBytes(bytes) {
|
|
66
|
-
const units = ["B", "KB", "MB", "GB"];
|
|
67
|
-
let v = bytes;
|
|
68
|
-
let u = 0;
|
|
69
|
-
while (v >= 1024 && u < units.length - 1) {
|
|
70
|
-
v /= 1024;
|
|
71
|
-
u++;
|
|
72
|
-
}
|
|
73
|
-
return `${v.toFixed(2)} ${units[u]}`;
|
|
74
|
-
}
|
|
75
|
-
function printRatio(beforeBytes, afterBytes, files) {
|
|
76
|
-
const saved = beforeBytes - afterBytes;
|
|
77
|
-
const pct = beforeBytes === 0 ? 0 : saved / beforeBytes * 100;
|
|
78
|
-
console.log(`
|
|
79
|
-
compress-shader-literals`);
|
|
80
|
-
console.log("────────────────────────");
|
|
81
|
-
console.log(`${fmtBytes(beforeBytes)} → ${fmtBytes(afterBytes)}`);
|
|
82
|
-
console.log(`saved: ${fmtBytes(saved)} (${pct.toFixed(2)}% smaller)`);
|
|
83
|
-
console.log(`shaders: ${files}
|
|
84
|
-
`);
|
|
85
|
-
}
|
|
86
66
|
var compressShaderLiterals = createUnplugin((options = {}) => {
|
|
87
67
|
const tags = options.tags || ["glsl", "wgsl", "shader"];
|
|
68
|
+
const minify = options.transform || minifyShader;
|
|
88
69
|
const filter = createFilter(options.include || [/\.[jt]sx?$/], options.exclude || [/node_modules/, /dist/]);
|
|
89
|
-
|
|
70
|
+
let beforeText = "";
|
|
71
|
+
let afterText = "";
|
|
90
72
|
return {
|
|
91
73
|
name: "compress-shader-literals",
|
|
92
74
|
enforce: "pre",
|
|
@@ -98,31 +80,32 @@ var compressShaderLiterals = createUnplugin((options = {}) => {
|
|
|
98
80
|
const literals = extractShaderLiterals(code, tags);
|
|
99
81
|
if (literals.length === 0)
|
|
100
82
|
return null;
|
|
83
|
+
if (options.debug) {
|
|
84
|
+
console.log(`[compress-shader-literals] ${id}: ${literals.length} literal(s) — ${literals.map((l) => l.tag).join(", ")}`);
|
|
85
|
+
}
|
|
101
86
|
const ms = new MagicString(code);
|
|
102
87
|
let hasChanges = false;
|
|
103
88
|
for (const literal of literals) {
|
|
104
|
-
const minified =
|
|
89
|
+
const minified = minify(literal.value);
|
|
105
90
|
if (literal.value !== minified) {
|
|
106
91
|
ms.overwrite(literal.start, literal.end, `\`${minified}\``);
|
|
107
92
|
hasChanges = true;
|
|
108
93
|
}
|
|
94
|
+
if (options.outputRatio) {
|
|
95
|
+
beforeText += literal.value;
|
|
96
|
+
afterText += minified;
|
|
97
|
+
}
|
|
109
98
|
}
|
|
110
99
|
if (!hasChanges)
|
|
111
100
|
return null;
|
|
112
|
-
const resultCode = ms.toString();
|
|
113
|
-
if (options.outputRatio) {
|
|
114
|
-
stats.before += Buffer.byteLength(code);
|
|
115
|
-
stats.after += Buffer.byteLength(resultCode);
|
|
116
|
-
stats.files += 1;
|
|
117
|
-
}
|
|
118
101
|
return {
|
|
119
|
-
code:
|
|
102
|
+
code: ms.toString(),
|
|
120
103
|
map: ms.generateMap({ hires: true, source: id })
|
|
121
104
|
};
|
|
122
105
|
},
|
|
123
106
|
buildEnd() {
|
|
124
|
-
if (options.outputRatio &&
|
|
125
|
-
|
|
107
|
+
if (options.outputRatio && beforeText) {
|
|
108
|
+
diff(snap.text(beforeText), snap.text(afterText)).print();
|
|
126
109
|
}
|
|
127
110
|
}
|
|
128
111
|
};
|
package/dist/index.js.br
CHANGED
|
Binary file
|
package/dist/index.js.gz
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compress-shader-literals",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Size matters. Minify GLSL/WGSL shader template literals at build time — universal plugin for Vite, Rollup, webpack, esbuild & more.",
|
|
6
6
|
"keywords": [
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
"glsl",
|
|
9
9
|
"wgsl",
|
|
10
10
|
"minify",
|
|
11
|
+
"minification",
|
|
11
12
|
"compress",
|
|
13
|
+
"compression",
|
|
14
|
+
"bundle-size",
|
|
15
|
+
"optimization",
|
|
16
|
+
"code-size",
|
|
17
|
+
"typescript",
|
|
12
18
|
"webgl",
|
|
13
19
|
"webgpu",
|
|
14
20
|
"three",
|
|
@@ -36,8 +42,10 @@
|
|
|
36
42
|
},
|
|
37
43
|
"main": "./dist/index.js",
|
|
38
44
|
"module": "./dist/index.js",
|
|
45
|
+
"types": "./dist/index.d.ts",
|
|
39
46
|
"exports": {
|
|
40
47
|
".": {
|
|
48
|
+
"types": "./dist/index.d.ts",
|
|
41
49
|
"import": "./dist/index.js"
|
|
42
50
|
}
|
|
43
51
|
},
|
|
@@ -46,9 +54,11 @@
|
|
|
46
54
|
],
|
|
47
55
|
"sideEffects": false,
|
|
48
56
|
"scripts": {
|
|
49
|
-
"build": "bun build src/plugin.js --outdir dist --entry-naming index.js --target node --format esm --external @babel/parser --external @babel/traverse --external @rollup/pluginutils --external magic-string --external unplugin && node scripts/compress-dist.js",
|
|
57
|
+
"build": "bun build src/plugin.js --outdir dist --entry-naming index.js --target node --format esm --external @babel/parser --external @babel/traverse --external @rollup/pluginutils --external byte-snap --external magic-string --external unplugin && cp src/index.d.ts dist/index.d.ts && node scripts/compress-dist.js",
|
|
58
|
+
"typecheck": "tsc --noEmit --strict --skipLibCheck src/index.d.ts",
|
|
50
59
|
"test": "bun test",
|
|
51
60
|
"test:run": "bun test",
|
|
61
|
+
"test:validate": "cd tests && bun install && node validate.js",
|
|
52
62
|
"test:e2e": "cd tests && bun install && node e2e.js",
|
|
53
63
|
"format": "prettier --write .",
|
|
54
64
|
"format:check": "prettier --check .",
|
|
@@ -59,11 +69,13 @@
|
|
|
59
69
|
"@babel/parser": "^8.0.0",
|
|
60
70
|
"@babel/traverse": "^8.0.0",
|
|
61
71
|
"@rollup/pluginutils": "^5.4.0",
|
|
72
|
+
"byte-snap": "^1.0.3",
|
|
62
73
|
"magic-string": "^0.30.21",
|
|
63
74
|
"unplugin": "^3.0.0"
|
|
64
75
|
},
|
|
65
76
|
"devDependencies": {
|
|
66
77
|
"@trivago/prettier-plugin-sort-imports": "^5.0.0",
|
|
67
|
-
"prettier": "^3.0.0"
|
|
78
|
+
"prettier": "^3.0.0",
|
|
79
|
+
"typescript": "^5.6.0"
|
|
68
80
|
}
|
|
69
81
|
}
|