compress-shader-literals 1.0.1 → 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 CHANGED
@@ -9,61 +9,39 @@
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
- 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.
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
  ![Alt Preview](./assets/preview.png)
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-28_
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
- npm i -D compress-shader-literals
47
- # or: bun add -d compress-shader-literals
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
- Pick your bundler — same plugin, same options:
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
- // Vite vite.config.js
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
- It finds tagged and comment-prefixed literals and yes, the comment form keeps your editor's syntax highlighting:
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?$/]` | 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 |
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,31 @@ extractShaderLiterals('const v = glsl`void main() {}`');
102
78
  minifyShader('// comment\nvoid main() {}'); // → 'void main() {}'
103
79
  ```
104
80
 
105
- ## How it works
81
+ ## Stats
82
+
83
+ Real shaders shipped by popular libraries, run through the built-in minifier:
106
84
 
107
- Nothing clever, which is the point:
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_
108
96
 
109
- 1. Parses each matched file with Babel (TS/JSX aware).
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.
97
+ <!-- STATS:END -->
98
+
99
+ ## How it works
113
100
 
114
- One [unplugin](https://github.com/unjs/unplugin) covers **Vite, Rollup, webpack, esbuild, Rspack, Rolldown & Farm**.
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.
115
106
 
116
107
  ## Issues & compatibility
117
108
 
package/dist/index.cjs CHANGED
@@ -1,3 +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&&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,`
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
2
  `).replace(/\/\*[\s\S]*?\*\//g,``).replace(/\/\/.*$/gm,``).replace(/[ \t]+/g,` `).replace(/\n{2,}/g,`
3
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, {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "compress-shader-literals",
3
- "version": "1.0.1",
3
+ "version": "1.1.3",
4
4
  "type": "module",
5
- "description": "Size matters. Minify GLSL/WGSL shader template literals at build time universal plugin for Vite, Rollup, webpack, esbuild & more.",
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",