compress-shader-literals 1.1.3 → 1.3.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 CHANGED
@@ -9,23 +9,22 @@
9
9
  [![npm downloads](https://img.shields.io/npm/dm/compress-shader-literals?color=success)](https://www.npmjs.com/package/compress-shader-literals)
10
10
  [![license](https://img.shields.io/npm/l/compress-shader-literals?color=blue)](./LICENSE)
11
11
 
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.
12
+ A tiny build-time minifier for GLSL & WGSL shaders written as template literals in your JS/TS. Strips comments + whitespace — any bundler, no renaming, no toolchain, no runtime cost.
13
13
 
14
- ![Alt Preview](./assets/preview.png)
14
+ ![Alt Preview](./assets/preview.gif)
15
15
 
16
16
  ## Install
17
17
 
18
+ [![NPM](https://nodei.co/npm/compress-shader-literals.png)](https://www.npmjs.com/package/compress-shader-literals)
19
+
18
20
  ```sh
19
21
  bun add -d compress-shader-literals
20
- # or: npm i -D compress-shader-literals
21
22
  ```
22
23
 
23
24
  ## About
24
25
 
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.
26
+ - Removes comments, collapses whitespace, joins statements, and trims space around delimiters. Whitespace and comments only.
27
+ - No renaming, no dead-code removal, no operator-space removal — output stays valid.
29
28
  - Runs before your bundler's own minifier.
30
29
 
31
30
  ## Usage
@@ -84,15 +83,31 @@ Real shaders shipped by popular libraries, run through the built-in minifier:
84
83
 
85
84
  <!-- STATS:START -->
86
85
 
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_
86
+ | Package | Shaders | Before | After | Saved |
87
+ | ----------------------------- | ------: | ----------: | ----------: | --------: |
88
+ | `vtk.js` | 142 | 276,617 B | 159,634 B | **42.3%** |
89
+ | `three-stdlib` | 370 | 429,350 B | 272,486 B | **36.5%** |
90
+ | `curtainsjs` | 7 | 3,406 B | 2,352 B | **30.9%** |
91
+ | `hydra-synth` | 15 | 3,852 B | 2,675 B | **30.6%** |
92
+ | `cesium` | 546 | 951,897 B | 664,581 B | **30.2%** |
93
+ | `troika-three-utils` | 4 | 168 B | 120 B | **28.6%** |
94
+ | `pixi.js` | 162 | 75,768 B | 56,152 B | **25.9%** |
95
+ | `shader-park-core` | 18 | 10,794 B | 8,007 B | **25.8%** |
96
+ | `@luma.gl/shadertools` | 24 | 149,192 B | 111,095 B | **25.5%** |
97
+ | `three` | 281 | 240,906 B | 185,520 B | **23.0%** |
98
+ | `playcanvas` | 856 | 1,297,844 B | 1,039,365 B | **19.9%** |
99
+ | `ogl` | 22 | 6,109 B | 4,925 B | **19.4%** |
100
+ | `deck.gl` | 132 | 242,113 B | 198,706 B | **17.9%** |
101
+ | `@paper-design/shaders` | 30 | 142,466 B | 122,036 B | **14.3%** |
102
+ | `@deck.gl/layers` | 104 | 223,902 B | 195,827 B | **12.5%** |
103
+ | `@deck.gl/core` | 40 | 17,746 B | 15,738 B | **11.3%** |
104
+ | `@deck.gl/aggregation-layers` | 56 | 43,713 B | 39,094 B | **10.6%** |
105
+ | `@luma.gl/engine` | 29 | 11,357 B | 10,384 B | **8.6%** |
106
+ | `@babylonjs/core` | 349 | 669,740 B | 661,013 B | **1.3%** |
107
+ | `postprocessing` | 136 | 179,705 B | 179,705 B | **0.0%** |
108
+ | **Total** | 3323 | 4,976,645 B | 3,929,415 B | **21.0%** |
109
+
110
+ _3323 shaders · 2348/2348 parseable GLSL verified valid after minify · [how this is measured](docs/stats.md) · 2026-07-01_
96
111
 
97
112
  <!-- STATS:END -->
98
113
 
@@ -100,7 +115,7 @@ _328 shaders · 303/303 parseable GLSL verified valid after minify · [how this
100
115
 
101
116
  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
117
  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.
118
+ 3. Strips comments, collapses whitespace, and joins statements onto one line keeping real newlines around `#` preprocessor directives and `\` line-continuations (which are newline-sensitive). Whitespace hugging a delimiter (`( ) { } ; ,`) is removed entirely; whitespace around operators (and `=`, to stay WGSL-generic-safe) is preserved, so adjacent tokens never merge.
104
119
  4. Rewrites the literal in place with [magic-string](https://github.com/Rich-Harris/magic-string), so sourcemaps stay intact.
105
120
  5. Runs as a `pre` transform, so your bundler's own minifier still sees the result.
106
121
 
package/dist/index.cjs CHANGED
@@ -1,3 +1,9 @@
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,`
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;
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=/\s*([(){};,])\s*/g,C=p.default.default||p.default,w=(e,t=m)=>{let n=new Set(t),r=_(t),i=[];try{C((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},T=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 r=!1,n=n.split(`
8
+ `).map(e=>{let t=e.startsWith(`#`)||r?e:e.replace(S,`$1`);return r=e.endsWith(`\\`),t}).join(`
9
+ `),n.trim()},E=(0,d.createUnplugin)((e={})=>{let t=e.tags||m,n=e.transform||T,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=w(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=E,exports.extractShaderLiterals=w,exports.minifyShader=T;
package/dist/index.js CHANGED
@@ -9,10 +9,10 @@ var s = [
9
9
  "glsl",
10
10
  "wgsl",
11
11
  "shader"
12
- ], c = [/\.[mc]?[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 = /\r\n/g, f = /\/\*[\s\S]*?\*\//g, p = /\/\/.*$/gm, m = /[ \t]+/g, h = /\s*([(){};,])\s*/g, g = o.default || o, _ = (e, t = s) => {
13
13
  let n = new Set(t), r = u(t), i = [];
14
14
  try {
15
- d(a(e, {
15
+ g(a(e, {
16
16
  sourceType: "module",
17
17
  plugins: [
18
18
  "typescript",
@@ -53,20 +53,27 @@ var s = [
53
53
  if (e.name !== "SyntaxError") throw e;
54
54
  }
55
55
  return 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 = {}) => {
57
- let a = i.tags || s, o = i.transform || p, u = e(i.include || c, i.exclude || l), d = "", m = "";
56
+ }, v = (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 r = !1, n = n.split("\n").map((e) => {
60
+ let t = e.startsWith("#") || r ? e : e.replace(h, "$1");
61
+ return r = e.endsWith("\\"), t;
62
+ }).join("\n"), n.trim();
63
+ }, y = i((i = {}) => {
64
+ let a = i.tags || s, o = i.transform || v, u = e(i.include || c, i.exclude || l), d = "", f = "";
58
65
  return {
59
66
  name: "compress-shader-literals",
60
67
  enforce: "pre",
61
68
  transform(e, t) {
62
69
  if (!u(t) || !a.some((t) => e.includes(t))) return null;
63
- let n = f(e, a);
70
+ let n = _(e, a);
64
71
  if (n.length === 0) return null;
65
72
  i.debug && console.log(`[compress-shader-literals] ${t}: ${n.length} literal(s) — ${n.map((e) => e.tag).join(", ")}`);
66
73
  let s = new r(e), c = !1;
67
74
  for (let e of n) {
68
75
  let t = o(e.value);
69
- e.value !== t && (s.overwrite(e.start, e.end, `\`${t}\``), c = !0), i.outputRatio && (d += e.value, m += t);
76
+ e.value !== t && (s.overwrite(e.start, e.end, `\`${t}\``), c = !0), i.outputRatio && (d += e.value, f += t);
70
77
  }
71
78
  return c ? {
72
79
  code: s.toString(),
@@ -77,9 +84,9 @@ var s = [
77
84
  } : null;
78
85
  },
79
86
  buildEnd() {
80
- i.outputRatio && d && t(n.text(d), n.text(m)).print();
87
+ i.outputRatio && d && t(n.text(d), n.text(f)).print();
81
88
  }
82
89
  };
83
90
  });
84
91
  //#endregion
85
- export { m as compressShaderLiterals, f as extractShaderLiterals, p as minifyShader };
92
+ export { y as compressShaderLiterals, _ as extractShaderLiterals, v as minifyShader };
package/package.json CHANGED
@@ -1,45 +1,8 @@
1
1
  {
2
2
  "name": "compress-shader-literals",
3
- "version": "1.1.3",
3
+ "version": "1.3.0",
4
4
  "type": "module",
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
- "keywords": [
7
- "shader",
8
- "glsl",
9
- "wgsl",
10
- "minify",
11
- "minification",
12
- "compress",
13
- "compression",
14
- "bundle-size",
15
- "optimization",
16
- "code-size",
17
- "typescript",
18
- "webgl",
19
- "webgpu",
20
- "three",
21
- "threejs",
22
- "ogl",
23
- "react-three-fiber",
24
- "shader-park",
25
- "curtainsjs",
26
- "shadertoy",
27
- "vite-plugin",
28
- "rollup-plugin",
29
- "webpack-plugin",
30
- "esbuild-plugin",
31
- "unplugin"
32
- ],
33
- "license": "MIT",
34
- "author": "jayF0x",
35
- "repository": {
36
- "type": "git",
37
- "url": "git+https://github.com/jayf0x/compress-shader-literals.git"
38
- },
39
- "homepage": "https://github.com/jayf0x/compress-shader-literals#readme",
40
- "bugs": {
41
- "url": "https://github.com/jayf0x/compress-shader-literals/issues"
42
- },
5
+ "description": "✂️ Strip comments & whitespace from GLSL/WGSL shader literals in your JS/TS at build time any bundler, no toolchain, no runtime cost.",
43
6
  "main": "./dist/index.cjs",
44
7
  "module": "./dist/index.js",
45
8
  "types": "./dist/index.d.ts",
@@ -63,6 +26,8 @@
63
26
  "test:build": "bun run build && node tests/build-smoke.js",
64
27
  "test:validate": "cd tests && bun install && node validate.js",
65
28
  "test:e2e": "cd tests && bun install && node e2e.js",
29
+ "test:dump": "cd tests && bun install && node dump-chunks.js",
30
+ "tests:next": "cd tests && bun install && node experimental.js",
66
31
  "format": "prettier --write .",
67
32
  "format:check": "prettier --check .",
68
33
  "npm:deploy": "bash ./scripts/publish-npm.sh",
@@ -73,7 +38,7 @@
73
38
  "@babel/parser": "^8.0.0",
74
39
  "@babel/traverse": "^8.0.0",
75
40
  "@rollup/pluginutils": "^5.4.0",
76
- "byte-snap": "^1.0.6",
41
+ "byte-snap": "^1.1.0",
77
42
  "magic-string": "^0.30.21",
78
43
  "unplugin": "^3.0.0"
79
44
  },
@@ -93,5 +58,42 @@
93
58
  "path": "dist/index.js",
94
59
  "limit": "1.7 kB"
95
60
  }
61
+ ],
62
+ "license": "MIT",
63
+ "author": "jayF0x",
64
+ "repository": {
65
+ "type": "git",
66
+ "url": "git+https://github.com/jayf0x/compress-shader-literals.git"
67
+ },
68
+ "homepage": "https://github.com/jayf0x/compress-shader-literals#readme",
69
+ "bugs": {
70
+ "url": "https://github.com/jayf0x/compress-shader-literals/issues"
71
+ },
72
+ "keywords": [
73
+ "shader",
74
+ "glsl",
75
+ "wgsl",
76
+ "minify",
77
+ "minification",
78
+ "compress",
79
+ "compression",
80
+ "bundle-size",
81
+ "optimization",
82
+ "code-size",
83
+ "typescript",
84
+ "webgl",
85
+ "webgpu",
86
+ "three",
87
+ "threejs",
88
+ "ogl",
89
+ "react-three-fiber",
90
+ "shader-park",
91
+ "curtainsjs",
92
+ "shadertoy",
93
+ "vite-plugin",
94
+ "rollup-plugin",
95
+ "webpack-plugin",
96
+ "esbuild-plugin",
97
+ "unplugin"
96
98
  ]
97
99
  }