compress-shader-literals 1.0.1 → 1.2.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/README.md +50 -54
- package/dist/index.cjs +7 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -8
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -9,61 +9,41 @@
|
|
|
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
|
-
##
|
|
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%** |
|
|
16
|
+
## Install
|
|
30
17
|
|
|
31
|
-
|
|
18
|
+
[](https://www.npmjs.com/package/compress-shader-literals)
|
|
32
19
|
|
|
33
|
-
|
|
20
|
+
```sh
|
|
21
|
+
bun add -d compress-shader-literals
|
|
22
|
+
# or: npm i -D compress-shader-literals
|
|
23
|
+
```
|
|
34
24
|
|
|
35
|
-
|
|
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> -->
|
|
25
|
+
## About
|
|
42
26
|
|
|
43
|
-
|
|
27
|
+
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.
|
|
44
28
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```
|
|
29
|
+
- Removes comments, collapses whitespace. Nothing else.
|
|
30
|
+
- No renaming, no dead-code removal — output stays valid and readable.
|
|
31
|
+
- Runs before your bundler's own minifier.
|
|
49
32
|
|
|
50
33
|
## Usage
|
|
51
34
|
|
|
52
|
-
|
|
35
|
+
One [unplugin](https://github.com/unjs/unplugin) plugin, same API for every bundler:
|
|
53
36
|
|
|
54
37
|
```js
|
|
55
38
|
import { compressShaderLiterals } from 'compress-shader-literals';
|
|
56
39
|
|
|
57
|
-
//
|
|
40
|
+
// vite.config.js
|
|
58
41
|
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
42
|
```
|
|
65
43
|
|
|
66
|
-
|
|
44
|
+
For Rollup, webpack, esbuild, Rspack, Rolldown or Farm, call the matching method — `.rollup()`, `.webpack()`, `.esbuild()`, `.rspack()`, `.rolldown()`, `.farm()` — with the same options.
|
|
45
|
+
|
|
46
|
+
Finds tagged and comment-prefixed literals. The comment form keeps editor syntax highlighting:
|
|
67
47
|
|
|
68
48
|
```ts
|
|
69
49
|
const vert = glsl`
|
|
@@ -78,18 +58,16 @@ const frag = /* wgsl */ `
|
|
|
78
58
|
`;
|
|
79
59
|
```
|
|
80
60
|
|
|
81
|
-
Both collapse to a single tight line. No comments, no padding, no touched source files.
|
|
82
|
-
|
|
83
61
|
**Options**
|
|
84
62
|
|
|
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
|
|
63
|
+
| Option | Default | Description |
|
|
64
|
+
| ------------- | ---------------------------- | --------------------------------------------------- |
|
|
65
|
+
| `tags` | `['glsl', 'wgsl', 'shader']` | Tag names / comment markers to match |
|
|
66
|
+
| `include` | `[/\.[mc]?[jt]sx?$/]` | Files to process — the JS/TS family Babel can parse |
|
|
67
|
+
| `exclude` | `[/node_modules/, /dist/]` | Files to skip — dependencies are skipped by default |
|
|
68
|
+
| `outputRatio` | `false` | Print a bytes-saved summary after build |
|
|
69
|
+
| `transform` | built-in `minifyShader` | Custom minifier — `(shader: string) => string` |
|
|
70
|
+
| `debug` | `false` | Log each file's discovered literals to the console |
|
|
93
71
|
|
|
94
72
|
**Programmatic API** — the two core helpers are exported for tooling authors (validators, ESLint rules, CLIs), no plugin required:
|
|
95
73
|
|
|
@@ -102,16 +80,34 @@ extractShaderLiterals('const v = glsl`void main() {}`');
|
|
|
102
80
|
minifyShader('// comment\nvoid main() {}'); // → 'void main() {}'
|
|
103
81
|
```
|
|
104
82
|
|
|
105
|
-
##
|
|
83
|
+
## Stats
|
|
84
|
+
|
|
85
|
+
Real shaders shipped by popular libraries, run through the built-in minifier:
|
|
106
86
|
|
|
107
|
-
|
|
87
|
+
<!-- STATS:START -->
|
|
88
|
+
|
|
89
|
+
| Package | Shaders | Before | After | Saved |
|
|
90
|
+
| ----------------------- | ------: | ----------: | ----------: | --------: |
|
|
91
|
+
| `curtainsjs` | 7 | 3,406 B | 2,485 B | **27.0%** |
|
|
92
|
+
| `pixi.js` | 162 | 75,768 B | 59,432 B | **21.6%** |
|
|
93
|
+
| `shader-park-core` | 18 | 10,794 B | 8,721 B | **19.2%** |
|
|
94
|
+
| `three` | 281 | 240,772 B | 197,399 B | **18.0%** |
|
|
95
|
+
| `ogl` | 22 | 6,109 B | 5,182 B | **15.2%** |
|
|
96
|
+
| `@paper-design/shaders` | 30 | 142,466 B | 129,723 B | **8.9%** |
|
|
97
|
+
| `@babylonjs/core` | 349 | 669,740 B | 664,617 B | **0.8%** |
|
|
98
|
+
| **Total** | 869 | 1,149,055 B | 1,067,559 B | **7.1%** |
|
|
99
|
+
|
|
100
|
+
_869 shaders · 558/558 parseable GLSL verified valid after minify · [how this is measured](docs/stats.md) · 2026-07-01_
|
|
108
101
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
4. Runs as a `pre` transform, so your bundler's own minifier still sees the result.
|
|
102
|
+
<!-- STATS:END -->
|
|
103
|
+
|
|
104
|
+
## How it works
|
|
113
105
|
|
|
114
|
-
|
|
106
|
+
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).
|
|
107
|
+
2. Finds tagged (`` glsl`…` ``) and comment-prefixed (`/* glsl */ \`…\``) literals, skipping any with `${…}` interpolation.
|
|
108
|
+
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.
|
|
109
|
+
4. Rewrites the literal in place with [magic-string](https://github.com/Rich-Harris/magic-string), so sourcemaps stay intact.
|
|
110
|
+
5. Runs as a `pre` transform, so your bundler's own minifier still sees the result.
|
|
115
111
|
|
|
116
112
|
## Issues & compatibility
|
|
117
113
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
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,
|
|
2
|
-
`).replace(
|
|
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=[/\.[mc]?[jt]sx?$/],g=[/node_modules/,/dist/],_=e=>RegExp(`^\\s*(${e.join(`|`)})\\s*$`),v=/\r\n/g,y=/\/\*[\s\S]*?\*\//g,b=/\/\/.*$/gm,x=/[ \t]+/g,S=p.default.default||p.default,C=(e,t=m)=>{let n=new Set(t),r=_(t),i=[];try{S((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},w=e=>{let t=e.replace(v,`
|
|
2
|
+
`).replace(y,``).replace(b,``).split(`
|
|
3
|
+
`).map(e=>e.replace(x,` `).trim()).filter(Boolean),n=``,r=!1;for(let e of t)e.startsWith(`#`)||r?n+=(n&&!n.endsWith(`
|
|
4
|
+
`)?`
|
|
5
|
+
`:``)+e+`
|
|
6
|
+
`:n+=n===``||n.endsWith(`
|
|
7
|
+
`)?e:` `+e,r=e.endsWith(`\\`);return n.trim()},T=(0,d.createUnplugin)((e={})=>{let t=e.tags||m,n=e.transform||w,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=C(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=T,exports.extractShaderLiterals=C,exports.minifyShader=w;
|
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,10 +9,10 @@ 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,
|
|
12
|
+
], c = [/\.[mc]?[jt]sx?$/], l = [/node_modules/, /dist/], u = (e) => RegExp(`^\\s*(${e.join("|")})\\s*$`), d = /\r\n/g, f = /\/\*[\s\S]*?\*\//g, p = /\/\/.*$/gm, m = /[ \t]+/g, h = o.default || o, g = (e, t = s) => {
|
|
13
13
|
let n = new Set(t), r = u(t), i = [];
|
|
14
14
|
try {
|
|
15
|
-
|
|
15
|
+
h(a(e, {
|
|
16
16
|
sourceType: "module",
|
|
17
17
|
plugins: [
|
|
18
18
|
"typescript",
|
|
@@ -53,20 +53,24 @@ var s = [
|
|
|
53
53
|
if (e.name !== "SyntaxError") throw e;
|
|
54
54
|
}
|
|
55
55
|
return i;
|
|
56
|
-
},
|
|
57
|
-
let
|
|
56
|
+
}, _ = (e) => {
|
|
57
|
+
let t = e.replace(d, "\n").replace(f, "").replace(p, "").split("\n").map((e) => e.replace(m, " ").trim()).filter(Boolean), n = "", r = !1;
|
|
58
|
+
for (let e of t) e.startsWith("#") || r ? n += (n && !n.endsWith("\n") ? "\n" : "") + e + "\n" : n += n === "" || n.endsWith("\n") ? e : " " + e, r = e.endsWith("\\");
|
|
59
|
+
return n.trim();
|
|
60
|
+
}, v = i((i = {}) => {
|
|
61
|
+
let a = i.tags || s, o = i.transform || _, u = e(i.include || c, i.exclude || l), d = "", f = "";
|
|
58
62
|
return {
|
|
59
63
|
name: "compress-shader-literals",
|
|
60
64
|
enforce: "pre",
|
|
61
65
|
transform(e, t) {
|
|
62
66
|
if (!u(t) || !a.some((t) => e.includes(t))) return null;
|
|
63
|
-
let n =
|
|
67
|
+
let n = g(e, a);
|
|
64
68
|
if (n.length === 0) return null;
|
|
65
69
|
i.debug && console.log(`[compress-shader-literals] ${t}: ${n.length} literal(s) — ${n.map((e) => e.tag).join(", ")}`);
|
|
66
70
|
let s = new r(e), c = !1;
|
|
67
71
|
for (let e of n) {
|
|
68
72
|
let t = o(e.value);
|
|
69
|
-
e.value !== t && (s.overwrite(e.start, e.end, `\`${t}\``), c = !0), i.outputRatio && (d += e.value,
|
|
73
|
+
e.value !== t && (s.overwrite(e.start, e.end, `\`${t}\``), c = !0), i.outputRatio && (d += e.value, f += t);
|
|
70
74
|
}
|
|
71
75
|
return c ? {
|
|
72
76
|
code: s.toString(),
|
|
@@ -77,9 +81,9 @@ var s = [
|
|
|
77
81
|
} : null;
|
|
78
82
|
},
|
|
79
83
|
buildEnd() {
|
|
80
|
-
i.outputRatio && d && t(n.text(d), n.text(
|
|
84
|
+
i.outputRatio && d && t(n.text(d), n.text(f)).print();
|
|
81
85
|
}
|
|
82
86
|
};
|
|
83
87
|
});
|
|
84
88
|
//#endregion
|
|
85
|
-
export {
|
|
89
|
+
export { v as compressShaderLiterals, g as extractShaderLiterals, _ as minifyShader };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compress-shader-literals",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
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",
|
|
@@ -63,6 +63,8 @@
|
|
|
63
63
|
"test:build": "bun run build && node tests/build-smoke.js",
|
|
64
64
|
"test:validate": "cd tests && bun install && node validate.js",
|
|
65
65
|
"test:e2e": "cd tests && bun install && node e2e.js",
|
|
66
|
+
"test:dump": "cd tests && bun install && node dump-chunks.js",
|
|
67
|
+
"tests:next": "cd tests && bun install && node experimental.js",
|
|
66
68
|
"format": "prettier --write .",
|
|
67
69
|
"format:check": "prettier --check .",
|
|
68
70
|
"npm:deploy": "bash ./scripts/publish-npm.sh",
|
|
@@ -73,7 +75,7 @@
|
|
|
73
75
|
"@babel/parser": "^8.0.0",
|
|
74
76
|
"@babel/traverse": "^8.0.0",
|
|
75
77
|
"@rollup/pluginutils": "^5.4.0",
|
|
76
|
-
"byte-snap": "^1.0
|
|
78
|
+
"byte-snap": "^1.1.0",
|
|
77
79
|
"magic-string": "^0.30.21",
|
|
78
80
|
"unplugin": "^3.0.0"
|
|
79
81
|
},
|