compress-shader-literals 1.2.0 → 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,9 +9,9 @@
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
 
@@ -19,15 +19,12 @@ A build-time minifier that strips comments and whitespace from GLSL & WGSL shade
19
19
 
20
20
  ```sh
21
21
  bun add -d compress-shader-literals
22
- # or: npm i -D compress-shader-literals
23
22
  ```
24
23
 
25
24
  ## About
26
25
 
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.
28
-
29
- - Removes comments, collapses whitespace. Nothing else.
30
- - 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.
31
28
  - Runs before your bundler's own minifier.
32
29
 
33
30
  ## Usage
@@ -86,18 +83,31 @@ Real shaders shipped by popular libraries, run through the built-in minifier:
86
83
 
87
84
  <!-- STATS:START -->
88
85
 
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_
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_
101
111
 
102
112
  <!-- STATS:END -->
103
113
 
@@ -105,7 +115,7 @@ _869 shaders · 558/558 parseable GLSL verified valid after minify · [how this
105
115
 
106
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).
107
117
  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.
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.
109
119
  4. Rewrites the literal in place with [magic-string](https://github.com/Rich-Harris/magic-string), so sourcemaps stay intact.
110
120
  5. Runs as a `pre` transform, so your bundler's own minifier still sees the result.
111
121
 
package/dist/index.cjs CHANGED
@@ -1,7 +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=/\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,`
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
2
  `).replace(y,``).replace(b,``).split(`
3
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
4
  `)?`
5
5
  `:``)+e+`
6
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;
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 = /\r\n/g, f = /\/\*[\s\S]*?\*\//g, p = /\/\/.*$/gm, m = /[ \t]+/g, h = o.default || o, g = (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
- h(a(e, {
15
+ g(a(e, {
16
16
  sourceType: "module",
17
17
  plugins: [
18
18
  "typescript",
@@ -53,18 +53,21 @@ var s = [
53
53
  if (e.name !== "SyntaxError") throw e;
54
54
  }
55
55
  return i;
56
- }, _ = (e) => {
56
+ }, v = (e) => {
57
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
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 = "";
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 = "";
62
65
  return {
63
66
  name: "compress-shader-literals",
64
67
  enforce: "pre",
65
68
  transform(e, t) {
66
69
  if (!u(t) || !a.some((t) => e.includes(t))) return null;
67
- let n = g(e, a);
70
+ let n = _(e, a);
68
71
  if (n.length === 0) return null;
69
72
  i.debug && console.log(`[compress-shader-literals] ${t}: ${n.length} literal(s) — ${n.map((e) => e.tag).join(", ")}`);
70
73
  let s = new r(e), c = !1;
@@ -86,4 +89,4 @@ var s = [
86
89
  };
87
90
  });
88
91
  //#endregion
89
- export { v as compressShaderLiterals, g as extractShaderLiterals, _ 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.2.0",
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",
@@ -95,5 +58,42 @@
95
58
  "path": "dist/index.js",
96
59
  "limit": "1.7 kB"
97
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"
98
98
  ]
99
99
  }