compress-shader-literals 1.0.0 → 1.1.3
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 +49 -54
- package/dist/index.cjs +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -9,61 +9,39 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/compress-shader-literals)
|
|
10
10
|
[](./LICENSE)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
A build-time minifier that strips comments and whitespace from GLSL & WGSL shaders written as template literals in your JS/TS — in any bundler, with no renaming, no toolchain, and no runtime cost.
|
|
13
13
|
|
|
14
14
|

|
|
15
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 | 11,095 B | 7,788 B | **29.8%** |
|
|
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 | 272,176 B | 228,147 B | **16.2%** |
|
|
30
|
-
|
|
31
|
-
_Auto-generated by [`tests/e2e.js`](tests/e2e.js) · packages [verified](tests/validate.js) loadable · 2026-06-27_
|
|
32
|
-
|
|
33
|
-
<!-- STATS:END -->
|
|
34
|
-
|
|
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> -->
|
|
42
|
-
|
|
43
16
|
## Install
|
|
44
17
|
|
|
45
18
|
```sh
|
|
46
|
-
|
|
47
|
-
# or:
|
|
19
|
+
bun add -d compress-shader-literals
|
|
20
|
+
# or: npm i -D compress-shader-literals
|
|
48
21
|
```
|
|
49
22
|
|
|
23
|
+
## About
|
|
24
|
+
|
|
25
|
+
Shader comments and indentation are dead weight in the bundle — the GPU ignores them, the browser still downloads them. This strips them at build time.
|
|
26
|
+
|
|
27
|
+
- Removes comments, collapses whitespace. Nothing else.
|
|
28
|
+
- No renaming, no dead-code removal — output stays valid and readable.
|
|
29
|
+
- Runs before your bundler's own minifier.
|
|
30
|
+
|
|
50
31
|
## Usage
|
|
51
32
|
|
|
52
|
-
|
|
33
|
+
One [unplugin](https://github.com/unjs/unplugin) plugin, same API for every bundler:
|
|
53
34
|
|
|
54
35
|
```js
|
|
55
36
|
import { compressShaderLiterals } from 'compress-shader-literals';
|
|
56
37
|
|
|
57
|
-
//
|
|
38
|
+
// vite.config.js
|
|
58
39
|
export default { plugins: [compressShaderLiterals.vite({ outputRatio: true })] };
|
|
59
|
-
|
|
60
|
-
// Rollup rollup.config.js → compressShaderLiterals.rollup({ ... })
|
|
61
|
-
// webpack webpack.config.js → compressShaderLiterals.webpack({ ... })
|
|
62
|
-
// esbuild build script → compressShaderLiterals.esbuild({ ... })
|
|
63
|
-
// Rspack / Rolldown / Farm → .rspack() / .rolldown() / .farm()
|
|
64
40
|
```
|
|
65
41
|
|
|
66
|
-
|
|
42
|
+
For Rollup, webpack, esbuild, Rspack, Rolldown or Farm, call the matching method — `.rollup()`, `.webpack()`, `.esbuild()`, `.rspack()`, `.rolldown()`, `.farm()` — with the same options.
|
|
43
|
+
|
|
44
|
+
Finds tagged and comment-prefixed literals. The comment form keeps editor syntax highlighting:
|
|
67
45
|
|
|
68
46
|
```ts
|
|
69
47
|
const vert = glsl`
|
|
@@ -78,18 +56,16 @@ const frag = /* wgsl */ `
|
|
|
78
56
|
`;
|
|
79
57
|
```
|
|
80
58
|
|
|
81
|
-
Both collapse to a single tight line. No comments, no padding, no touched source files.
|
|
82
|
-
|
|
83
59
|
**Options**
|
|
84
60
|
|
|
85
|
-
| Option | Default | Description
|
|
86
|
-
| ------------- | ---------------------------- |
|
|
87
|
-
| `tags` | `['glsl', 'wgsl', 'shader']` | Tag names / comment markers to match
|
|
88
|
-
| `include` | `[/\.[jt]sx?$/]`
|
|
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
|
|
61
|
+
| Option | Default | Description |
|
|
62
|
+
| ------------- | ---------------------------- | --------------------------------------------------- |
|
|
63
|
+
| `tags` | `['glsl', 'wgsl', 'shader']` | Tag names / comment markers to match |
|
|
64
|
+
| `include` | `[/\.[mc]?[jt]sx?$/]` | Files to process — the JS/TS family Babel can parse |
|
|
65
|
+
| `exclude` | `[/node_modules/, /dist/]` | Files to skip — dependencies are skipped by default |
|
|
66
|
+
| `outputRatio` | `false` | Print a bytes-saved summary after build |
|
|
67
|
+
| `transform` | built-in `minifyShader` | Custom minifier — `(shader: string) => string` |
|
|
68
|
+
| `debug` | `false` | Log each file's discovered literals to the console |
|
|
93
69
|
|
|
94
70
|
**Programmatic API** — the two core helpers are exported for tooling authors (validators, ESLint rules, CLIs), no plugin required:
|
|
95
71
|
|
|
@@ -102,16 +78,35 @@ extractShaderLiterals('const v = glsl`void main() {}`');
|
|
|
102
78
|
minifyShader('// comment\nvoid main() {}'); // → 'void main() {}'
|
|
103
79
|
```
|
|
104
80
|
|
|
81
|
+
## Stats
|
|
82
|
+
|
|
83
|
+
Real shaders shipped by popular libraries, run through the built-in minifier:
|
|
84
|
+
|
|
85
|
+
<!-- STATS:START -->
|
|
86
|
+
|
|
87
|
+
| Package | Shaders | Before | After | Saved |
|
|
88
|
+
| ------------------ | ------: | --------: | --------: | --------: |
|
|
89
|
+
| `three` | 281 | 240,772 B | 203,428 B | **15.5%** |
|
|
90
|
+
| `ogl` | 22 | 6,109 B | 5,335 B | **12.7%** |
|
|
91
|
+
| `shader-park-core` | 18 | 10,794 B | 9,033 B | **16.3%** |
|
|
92
|
+
| `curtainsjs` | 7 | 3,406 B | 2,563 B | **24.8%** |
|
|
93
|
+
| **Total** | 328 | 261,081 B | 220,359 B | **15.6%** |
|
|
94
|
+
|
|
95
|
+
_328 shaders · 303/303 parseable GLSL verified valid after minify · [how this is measured](docs/stats.md) · 2026-06-29_
|
|
96
|
+
|
|
97
|
+
<!-- STATS:END -->
|
|
98
|
+
|
|
105
99
|
## How it works
|
|
106
100
|
|
|
107
|
-
|
|
101
|
+
1. Parses each matched file with Babel — `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.mts`, `.cts` (not `.vue`/`.svelte`/`.glsl`, which aren't whole-file JS).
|
|
102
|
+
2. Finds tagged (`` glsl`…` ``) and comment-prefixed (`/* glsl */ \`…\``) literals, skipping any with `${…}` interpolation.
|
|
103
|
+
3. Strips comments and collapses each run of whitespace to a single space or newline — never to nothing, so adjacent tokens stay separated and `#version`/`#define` lines survive.
|
|
104
|
+
4. Rewrites the literal in place with [magic-string](https://github.com/Rich-Harris/magic-string), so sourcemaps stay intact.
|
|
105
|
+
5. Runs as a `pre` transform, so your bundler's own minifier still sees the result.
|
|
108
106
|
|
|
109
|
-
|
|
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**.
|
|
112
|
-
4. Runs as a `pre` transform, so your bundler's own minifier still sees the result.
|
|
107
|
+
## Issues & compatibility
|
|
113
108
|
|
|
114
|
-
|
|
109
|
+
If you run into any problems — wrong output, a shader pattern that isn't picked up, or a library that doesn't play nicely — please [open an issue](https://github.com/jayf0x/compress-shader-literals/issues) or just mention which library you're using and I'll add it to the test suite.
|
|
115
110
|
|
|
116
111
|
## License
|
|
117
112
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("@rollup/pluginutils"),l=require("byte-snap"),u=require("magic-string");u=s(u,1);let d=require("unplugin"),f=require("@babel/parser"),p=require("@babel/traverse");p=s(p,1);var m=[`glsl`,`wgsl`,`shader`],h=[/\.[jt]sx?$/],g=[/node_modules/,/dist/],_=e=>RegExp(`^\\s*(${e.join(`|`)})\\s*$`),v=p.default.default||p.default,y=(e,t=m)=>{let n=new Set(t),r=_(t),i=[];try{v((0,f.parse)(e,{sourceType:`module`,plugins:[`typescript`,`jsx`,`decorators-legacy`],allowReturnOutsideFunction:!0}),{TaggedTemplateExpression(e){let{tag:t,quasi:r}=e.node,a=null;t.type===`Identifier`&&n.has(t.name)?a=t.name:t.type===`MemberExpression`&&t.property.type===`Identifier`&&n.has(t.property.name)&&(a=t.property.name),a&&i.push({tag:a,value:r.quasis.
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("@rollup/pluginutils"),l=require("byte-snap"),u=require("magic-string");u=s(u,1);let d=require("unplugin"),f=require("@babel/parser"),p=require("@babel/traverse");p=s(p,1);var m=[`glsl`,`wgsl`,`shader`],h=[/\.[mc]?[jt]sx?$/],g=[/node_modules/,/dist/],_=e=>RegExp(`^\\s*(${e.join(`|`)})\\s*$`),v=p.default.default||p.default,y=(e,t=m)=>{let n=new Set(t),r=_(t),i=[];try{v((0,f.parse)(e,{sourceType:`module`,plugins:[`typescript`,`jsx`,`decorators-legacy`],allowReturnOutsideFunction:!0}),{TaggedTemplateExpression(e){let{tag:t,quasi:r}=e.node,a=null;t.type===`Identifier`&&n.has(t.name)?a=t.name:t.type===`MemberExpression`&&t.property.type===`Identifier`&&n.has(t.property.name)&&(a=t.property.name),a&&r.expressions.length===0&&i.push({tag:a,value:r.quasis[0].value.raw,start:r.start,end:r.end})},TemplateLiteral(e){let t=e.node;if(t.expressions.length>0)return;let n=t.leadingComments||e.parentPath?.node?.leadingComments||[];for(let e of n){if(!e||e.type!==`CommentBlock`)continue;let n=e.value.match(r);if(n){i.push({tag:n[1],value:t.quasis[0].value.raw,start:t.start,end:t.end});break}}}})}catch(e){if(e.name!==`SyntaxError`)throw e}return i},b=e=>e.replace(/\r\n/g,`
|
|
2
|
+
`).replace(/\/\*[\s\S]*?\*\//g,``).replace(/\/\/.*$/gm,``).replace(/[ \t]+/g,` `).replace(/\n{2,}/g,`
|
|
2
3
|
`).trim(),x=(0,d.createUnplugin)((e={})=>{let t=e.tags||m,n=e.transform||b,r=(0,c.createFilter)(e.include||h,e.exclude||g),i=``,a=``;return{name:`compress-shader-literals`,enforce:`pre`,transform(o,s){if(!r(s)||!t.some(e=>o.includes(e)))return null;let c=y(o,t);if(c.length===0)return null;e.debug&&console.log(`[compress-shader-literals] ${s}: ${c.length} literal(s) — ${c.map(e=>e.tag).join(`, `)}`);let l=new u.default(o),d=!1;for(let t of c){let r=n(t.value);t.value!==r&&(l.overwrite(t.start,t.end,`\`${r}\``),d=!0),e.outputRatio&&(i+=t.value,a+=r)}return d?{code:l.toString(),map:l.generateMap({hires:!0,source:s})}:null},buildEnd(){e.outputRatio&&i&&(0,l.diff)(l.snap.text(i),l.snap.text(a)).print()}}});exports.compressShaderLiterals=x,exports.extractShaderLiterals=y,exports.minifyShader=b;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ type FilterPattern = string | RegExp | ReadonlyArray<string | RegExp> | null;
|
|
|
6
6
|
export interface CompressShaderLiteralsOptions {
|
|
7
7
|
/** Tag names / comment markers to match. Default: `['glsl', 'wgsl', 'shader']` */
|
|
8
8
|
tags?: string[];
|
|
9
|
-
/** Files to process. Default: `[/\.[jt]sx?$/]` */
|
|
9
|
+
/** Files to process. Default: `[/\.[mc]?[jt]sx?$/]` (the JS/TS family Babel can parse). */
|
|
10
10
|
include?: FilterPattern;
|
|
11
11
|
/** Files to skip. Default: `[/node_modules/, /dist/]` */
|
|
12
12
|
exclude?: FilterPattern;
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var s = [
|
|
|
9
9
|
"glsl",
|
|
10
10
|
"wgsl",
|
|
11
11
|
"shader"
|
|
12
|
-
], c = [/\.[jt]sx?$/], l = [/node_modules/, /dist/], u = (e) => RegExp(`^\\s*(${e.join("|")})\\s*$`), d = o.default || o, f = (e, t = s) => {
|
|
12
|
+
], c = [/\.[mc]?[jt]sx?$/], l = [/node_modules/, /dist/], u = (e) => RegExp(`^\\s*(${e.join("|")})\\s*$`), d = o.default || o, f = (e, t = s) => {
|
|
13
13
|
let n = new Set(t), r = u(t), i = [];
|
|
14
14
|
try {
|
|
15
15
|
d(a(e, {
|
|
@@ -23,22 +23,24 @@ var s = [
|
|
|
23
23
|
}), {
|
|
24
24
|
TaggedTemplateExpression(e) {
|
|
25
25
|
let { tag: t, quasi: r } = e.node, a = null;
|
|
26
|
-
t.type === "Identifier" && n.has(t.name) ? a = t.name : t.type === "MemberExpression" && t.property.type === "Identifier" && n.has(t.property.name) && (a = t.property.name), a && i.push({
|
|
26
|
+
t.type === "Identifier" && n.has(t.name) ? a = t.name : t.type === "MemberExpression" && t.property.type === "Identifier" && n.has(t.property.name) && (a = t.property.name), a && r.expressions.length === 0 && i.push({
|
|
27
27
|
tag: a,
|
|
28
|
-
value: r.quasis.
|
|
28
|
+
value: r.quasis[0].value.raw,
|
|
29
29
|
start: r.start,
|
|
30
30
|
end: r.end
|
|
31
31
|
});
|
|
32
32
|
},
|
|
33
33
|
TemplateLiteral(e) {
|
|
34
|
-
let t = e.node
|
|
34
|
+
let t = e.node;
|
|
35
|
+
if (t.expressions.length > 0) return;
|
|
36
|
+
let n = t.leadingComments || e.parentPath?.node?.leadingComments || [];
|
|
35
37
|
for (let e of n) {
|
|
36
38
|
if (!e || e.type !== "CommentBlock") continue;
|
|
37
39
|
let n = e.value.match(r);
|
|
38
40
|
if (n) {
|
|
39
41
|
i.push({
|
|
40
42
|
tag: n[1],
|
|
41
|
-
value: t.quasis.
|
|
43
|
+
value: t.quasis[0].value.raw,
|
|
42
44
|
start: t.start,
|
|
43
45
|
end: t.end
|
|
44
46
|
});
|
|
@@ -51,7 +53,7 @@ var s = [
|
|
|
51
53
|
if (e.name !== "SyntaxError") throw e;
|
|
52
54
|
}
|
|
53
55
|
return i;
|
|
54
|
-
}, p = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/[ \t]+/g, " ").replace(/\n{2,}/g, "\n").trim(), m = i((i = {}) => {
|
|
56
|
+
}, p = (e) => e.replace(/\r\n/g, "\n").replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/[ \t]+/g, " ").replace(/\n{2,}/g, "\n").trim(), m = i((i = {}) => {
|
|
55
57
|
let a = i.tags || s, o = i.transform || p, u = e(i.include || c, i.exclude || l), d = "", m = "";
|
|
56
58
|
return {
|
|
57
59
|
name: "compress-shader-literals",
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compress-shader-literals",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Minify GLSL/WGSL shaders in your JS/TS at build time. Drop-in plugin for Vite, Rollup, webpack, esbuild, Rspack, Rolldown & Farm.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"shader",
|
|
8
8
|
"glsl",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@babel/parser": "^8.0.0",
|
|
74
74
|
"@babel/traverse": "^8.0.0",
|
|
75
75
|
"@rollup/pluginutils": "^5.4.0",
|
|
76
|
-
"byte-snap": "^1.0.
|
|
76
|
+
"byte-snap": "^1.0.6",
|
|
77
77
|
"magic-string": "^0.30.21",
|
|
78
78
|
"unplugin": "^3.0.0"
|
|
79
79
|
},
|