diff --git a/package.json b/package.json index 71ebb6a..099f38c 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "type": "module", "exports": "./src/index.js", + "types": "./src/index.d.ts", "engines": { "node": ">=12" }, @@ -36,4 +37,4 @@ "esbuild": "^0.13.4", "glsl-noise": "^0.0.0" } -} +} \ No newline at end of file diff --git a/readme.md b/readme.md index d94f8fc..b433a33 100644 --- a/readme.md +++ b/readme.md @@ -30,6 +30,8 @@ build({ }).catch(() => process.exit(1)) ``` +You can also minify the imported shaders with `glslifyInline({ minify: true })`. + After that, you can use glslify normally with esbuild: ```js diff --git a/src/index.d.ts b/src/index.d.ts index ee00063..8e88163 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,4 +1,8 @@ import { Plugin } from 'esbuild' -declare function glslInline(): Plugin +type Options = { + minify?: boolean +} + +declare function glslInline(options?: Options): Plugin export { glslInline } diff --git a/src/index.js b/src/index.js index 1a97ab3..fb3787a 100644 --- a/src/index.js +++ b/src/index.js @@ -4,8 +4,9 @@ import fs from 'fs/promises' // a string and use it in another. Read more at: // https://github.com/onnovisser/babel-plugin-glsl#imported-function-names import compile from 'babel-plugin-glsl/lib/compile.js' +import { minifyShader } from './minifyShader.js' -export function glslifyInline() { +export function glslifyInline({ minify = false } = {}) { return { name: 'glslifyInline', setup(build) { @@ -36,7 +37,10 @@ export function glslifyInline() { return cache[glslifyImport] } - const contents = compile(glslifyImport) + let contents = compile(glslifyImport) + if (minify) { + contents = minifyShader(contents) + } cache[glslifyImport] = contents return contents }) diff --git a/src/minifyShader.js b/src/minifyShader.js new file mode 100644 index 0000000..931943a --- /dev/null +++ b/src/minifyShader.js @@ -0,0 +1,41 @@ +/** + * Minifies the given GLSL source code. + * + * Based on https://github.com/vwochnik/rollup-plugin-glsl + * Pasted from https://github.com/vanruesc/esbuild-plugin-glsl/blob/main/src/minifyShader.ts + * + * @param source The source code. + * @return The minified code. + */ + +export function minifyShader(source) { + const commentsRegExp = /[ \t]*(?:(?:\/\*[\s\S]*?\*\/)|(?:\/\/.*\n))/g + const symbolsRegExp = /\s*({|}|=|\*|,|\+|\/|>|<|&|\||\[|\]|\(|\)|-|!|;)\s*/g + + let result = source.replace(/\r/g, '').replace(commentsRegExp, '') + let wrap = false + + result = result + .split(/\n+/) + .reduce((acc, line) => { + line = line.trim().replace(/\s{2,}|\t/, ' ') + + if (line[0] === '#') { + if (wrap) { + acc.push('\n') + } + + acc.push(line, '\n') + wrap = false + } else { + line = line.replace(/(else)$/m, '$1 ') + acc.push(line.replace(symbolsRegExp, '$1')) + wrap = true + } + + return acc + }, []) + .join('') + + return result.replace(/\n{2,}/g, '\n') +} diff --git a/test/snapshots/test.js.md b/test/snapshots/test.js.md index d3f806c..c11979f 100644 --- a/test/snapshots/test.js.md +++ b/test/snapshots/test.js.md @@ -122,3 +122,35 @@ Generated by [AVA](https://avajs.dev). \`;␊ console.log(head, main);␊ ` + +## works with a basic example but minified + +> Snapshot 1 + + `// test/fixtures/basic.js␊ + var head = \`␊ + uniform float time;␊ + uniform float speed;␊ + vec3 mod289_2482186953(vec3 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 mod289_2482186953(vec4 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 permute_2482186953(vec4 x){return mod289_2482186953(((x*34.0)+1.0)*x);}vec4 taylorInvSqrt_2482186953(vec4 r){return 1.79284291400159-0.85373472095314*r;}float noise(vec3 v){const vec2 C=vec2(1.0/6.0,1.0/3.0);const vec4 D_2482186953=vec4(0.0,0.5,1.0,2.0);vec3 i=floor(v+dot(v,C.yyy));vec3 x0=v-i+dot(i,C.xxx);vec3 g_2482186953=step(x0.yzx,x0.xyz);vec3 l=1.0-g_2482186953;vec3 i1=min(g_2482186953.xyz,l.zxy);vec3 i2=max(g_2482186953.xyz,l.zxy);vec3 x1=x0-i1+C.xxx;vec3 x2=x0-i2+C.yyy;vec3 x3=x0-D_2482186953.yyy;i=mod289_2482186953(i);vec4 p=permute_2482186953(permute_2482186953(permute_2482186953(i.z+vec4(0.0,i1.z,i2.z,1.0))+i.y+vec4(0.0,i1.y,i2.y,1.0))+i.x+vec4(0.0,i1.x,i2.x,1.0));float n_=0.142857142857;vec3 ns=n_*D_2482186953.wyz-D_2482186953.xzx;vec4 j=p-49.0*floor(p*ns.z*ns.z);vec4 x_=floor(j*ns.z);vec4 y_=floor(j-7.0*x_);vec4 x=x_*ns.x+ns.yyyy;vec4 y=y_*ns.x+ns.yyyy;vec4 h=1.0-abs(x)-abs(y);vec4 b0=vec4(x.xy,y.xy);vec4 b1=vec4(x.zw,y.zw);vec4 s0=floor(b0)*2.0+1.0;vec4 s1=floor(b1)*2.0+1.0;vec4 sh=-step(h,vec4(0.0));vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;vec4 a1_2482186953=b1.xzyw+s1.xzyw*sh.zzww;vec3 p0_2482186953=vec3(a0.xy,h.x);vec3 p1=vec3(a0.zw,h.y);vec3 p2=vec3(a1_2482186953.xy,h.z);vec3 p3=vec3(a1_2482186953.zw,h.w);vec4 norm=taylorInvSqrt_2482186953(vec4(dot(p0_2482186953,p0_2482186953),dot(p1,p1),dot(p2,p2),dot(p3,p3)));p0_2482186953*=norm.x;p1*=norm.y;p2*=norm.z;p3*=norm.w;vec4 m=max(0.6-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.0);m=m*m;return 42.0*dot(m*m,vec4(dot(p0_2482186953,x0),dot(p1,x1),dot(p2,x2),dot(p3,x3)));}␊ + \`;␊ + var main = \`␊ + vec3 displacement = normal * noise(vec3(uv, time * speed));␊ + \`;␊ + console.log(head, main);␊ + ` + +## works with a basic example but minified + +> Snapshot 1 + + `// test/fixtures/basic.js␊ + var head = \`␊ + uniform float time;␊ + uniform float speed;␊ + vec3 mod289_2482186953(vec3 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 mod289_2482186953(vec4 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 permute_2482186953(vec4 x){return mod289_2482186953(((x*34.0)+1.0)*x);}vec4 taylorInvSqrt_2482186953(vec4 r){return 1.79284291400159-0.85373472095314*r;}float noise(vec3 v){const vec2 C=vec2(1.0/6.0,1.0/3.0);const vec4 D_2482186953=vec4(0.0,0.5,1.0,2.0);vec3 i=floor(v+dot(v,C.yyy));vec3 x0=v-i+dot(i,C.xxx);vec3 g_2482186953=step(x0.yzx,x0.xyz);vec3 l=1.0-g_2482186953;vec3 i1=min(g_2482186953.xyz,l.zxy);vec3 i2=max(g_2482186953.xyz,l.zxy);vec3 x1=x0-i1+C.xxx;vec3 x2=x0-i2+C.yyy;vec3 x3=x0-D_2482186953.yyy;i=mod289_2482186953(i);vec4 p=permute_2482186953(permute_2482186953(permute_2482186953(i.z+vec4(0.0,i1.z,i2.z,1.0))+i.y+vec4(0.0,i1.y,i2.y,1.0))+i.x+vec4(0.0,i1.x,i2.x,1.0));float n_=0.142857142857;vec3 ns=n_*D_2482186953.wyz-D_2482186953.xzx;vec4 j=p-49.0*floor(p*ns.z*ns.z);vec4 x_=floor(j*ns.z);vec4 y_=floor(j-7.0*x_);vec4 x=x_*ns.x+ns.yyyy;vec4 y=y_*ns.x+ns.yyyy;vec4 h=1.0-abs(x)-abs(y);vec4 b0=vec4(x.xy,y.xy);vec4 b1=vec4(x.zw,y.zw);vec4 s0=floor(b0)*2.0+1.0;vec4 s1=floor(b1)*2.0+1.0;vec4 sh=-step(h,vec4(0.0));vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;vec4 a1_2482186953=b1.xzyw+s1.xzyw*sh.zzww;vec3 p0_2482186953=vec3(a0.xy,h.x);vec3 p1=vec3(a0.zw,h.y);vec3 p2=vec3(a1_2482186953.xy,h.z);vec3 p3=vec3(a1_2482186953.zw,h.w);vec4 norm=taylorInvSqrt_2482186953(vec4(dot(p0_2482186953,p0_2482186953),dot(p1,p1),dot(p2,p2),dot(p3,p3)));p0_2482186953*=norm.x;p1*=norm.y;p2*=norm.z;p3*=norm.w;vec4 m=max(0.6-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.0);m=m*m;return 42.0*dot(m*m,vec4(dot(p0_2482186953,x0),dot(p1,x1),dot(p2,x2),dot(p3,x3)));}␊ + \`;␊ + var main = \`␊ + vec3 displacement = normal * noise(vec3(uv, time * speed));␊ + \`;␊ + console.log(head, main);␊ + ` diff --git a/test/snapshots/test.js.snap b/test/snapshots/test.js.snap index 0d40ed0..52433e5 100644 Binary files a/test/snapshots/test.js.snap and b/test/snapshots/test.js.snap differ diff --git a/test/test.js b/test/test.js index 96385ac..407e188 100644 --- a/test/test.js +++ b/test/test.js @@ -23,3 +23,20 @@ test('works with a basic example', async (t) => { t.snapshot(generated) }) + +test('works with a basic example but minified', async (t) => { + const input = path.resolve(__dirname, './fixtures/basic.js') + const output = path.resolve(__dirname, './fixtures/generated/basic-minified.js') + + await esbuild.build({ + entryPoints: [input], + outfile: output, + bundle: true, + format: 'esm', + plugins: [glslifyInline({ minify: true })], + }) + + const generated = await fs.readFile(output, 'utf-8') + + t.snapshot(generated) +})