Skip to content

Instantly share code, notes, and snippets.

@0b5vr
Last active April 3, 2024 03:11
Show Gist options
  • Save 0b5vr/09ee96ca2efbe5bf9d64dad7220e923b to your computer and use it in GitHub Desktop.
Save 0b5vr/09ee96ca2efbe5bf9d64dad7220e923b to your computer and use it in GitHub Desktop.

Revisions

  1. 0b5vr revised this gist Apr 3, 2024. 1 changed file with 63 additions and 49 deletions.
    112 changes: 63 additions & 49 deletions compeko.js
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,16 @@
    #!/usr/bin/env node
    #!/usr/bin/env -S deno run --allow-read --allow-write --allow-run

    // compeko - pack JavaScript into a self-extracting html+deflate
    // v1.1.1
    // v2.0.0

    // Copyright (c) 2022-2023 0b5vr
    // Copyright (c) 2022-2024 0b5vr
    // SPDX-License-Identifier: MIT

    // Usage:
    // - prepare a js code, which will be fed into `eval`
    // - install `node-zopfli` as your (dev-) dependency
    // - run: `node compeko.js input.js output.html`
    // - install Deno as your runtime
    // - install zopfli and make it visible via PATH
    // - run: `deno run --allow-read --allow-write --allow-run compeko.ts input.js output.html`

    // Shoutouts to:
    // - gasman, for pnginator ... https://gist.github.com/gasman/2560551
    @@ -19,60 +20,73 @@

    // =================================================================================================

    // -- modules --------------------------------------------------------------------------------------
    import { relative } from 'https://deno.land/[email protected]/path/relative.ts';
    import { expandGlob } from 'https://deno.land/[email protected]/fs/expand_glob.ts';

    // -- sanity check ---------------------------------------------------------------------------------
    if (Deno.args.length < 2) {
    console.error('Usage: deno run --allow-read --allow-write --allow-run compeko.ts input.js output.html');
    Deno.exit(1);
    }

    try {
    require( 'node-zopfli' );
    } catch ( e ) {
    console.error( e );
    console.error( `
    \x1b[31mMake sure you installed \x1b[35mnode-zopfli\x1b[31m !\x1b[0m` );
    process.exit( 1 );
    const zopfliHelp = new Deno.Command('zopfli', ['-h']);
    await zopfliHelp.output();
    } catch (e) {
    if (e instanceof Deno.errors.NotFound) {
    console.error('\x1b[31mzopfli is not installed or not visible via PATH\x1b[0m');
    Deno.exit(1);
    } else {
    throw e;
    }
    }

    if ( process.argv[ 3 ] == null ) {
    console.error( '\x1b[31mUsage: \x1b[35mnode compeko.js input.js output.html\x1b[0m' );
    process.exit( 1 );
    // -- file stuff -----------------------------------------------------------------------------------
    const inputGlob = Deno.args[0];
    const inputEntry = await expandGlob(inputGlob).next();
    const inputPath = inputEntry?.value?.path;

    if (!inputPath) {
    console.error(`\x1b[31mGlob did not match: ${inputGlob}\x1b[0m`);
    Deno.exit(1);
    }
    const inputPathRelative = relative('.', inputPath);
    console.info(`Input file: \x1b[34m${inputPathRelative}\x1b[0m`);

    // -- modules --------------------------------------------------------------------------------------
    const fs = require( 'fs' );
    const { resolve } = require( 'path' );
    const zopfli = require( 'node-zopfli' );
    const outputPath = Deno.args[1];
    console.info(`Output file: \x1b[34m${outputPath}\x1b[0m`);

    // -- main -----------------------------------------------------------------------------------------
    console.info( 'Compressing the file...' );

    ( async () => {
    const inputPath = resolve( process.cwd(), process.argv[ 2 ] );
    const outputPath = resolve( process.cwd(), process.argv[ 3 ] );

    const inputFile = await fs.promises.readFile( inputPath );
    const inputSize = inputFile.length;
    console.info( `Input size: \x1b[32m${ inputSize.toLocaleString() } bytes\x1b[0m` );

    const compressed = await zopfli.deflate( inputFile, {
    numiterations: 100, // increase this number to shave your last bytes
    blocksplitting: true,
    } );

    // extra: output deflate
    {
    const outputPathBase = outputPath.match( /(.*)\..+$/ )[ 1 ];
    const deflatePath = `${ outputPathBase }.deflate.bin`;
    await fs.promises.writeFile( deflatePath, compressed );
    }
    console.info('Compressing the file...');

    const inputFile = await Deno.readTextFile(inputPath);
    const inputSize = inputFile.length;
    console.info(`Input size: \x1b[32m${inputSize.toLocaleString()} bytes\x1b[0m`);

    const zopfli = new Deno.Command('zopfli', {
    args: ['-c', '-i100', '--deflate', inputPath],
    });
    const compressed = (await zopfli.output()).stdout;

    // extra: output deflate
    {
    const outputPathBase = outputPath.match(/(.*)\..+$/)[1];
    const deflatePath = `${outputPathBase}.deflate.bin`;
    await Deno.writeFile(deflatePath, compressed);
    }

    const header = '<svg onload="fetch`#`.then(t=>t.blob()).then(t=>new Response(t.slice(156).stream().pipeThrough(new DecompressionStream('deflate-raw'))).text()).then(eval)">';
    const headerBuffer = Buffer.alloc( header.length );
    headerBuffer.write( header );
    const header = '<svg onload="fetch`#`.then(t=>t.blob()).then(t=>new Response(t.slice(156).stream().pipeThrough(new DecompressionStream(\'deflate-raw\'))).text()).then(eval)">';
    const headerBuffer = new TextEncoder().encode(header);

    const concated = Buffer.concat( [ headerBuffer, compressed ] );
    const concated = new Uint8Array(headerBuffer.length + compressed.length);
    concated.set(headerBuffer);
    concated.set(compressed, headerBuffer.length);

    const outputSize = concated.length;
    const percentage = ( 100.0 * ( outputSize / inputSize ) ).toFixed( 3 );
    console.info( `Output size: \x1b[32m${ outputSize.toLocaleString() } bytes\x1b[0m (${ percentage } %)` );
    const outputSize = concated.length;
    const percentage = (100.0 * (outputSize / inputSize)).toFixed(3);
    console.info(`Output size: \x1b[32m${outputSize.toLocaleString()} bytes\x1b[0m (${percentage} %)`);

    await fs.promises.writeFile( outputPath, concated );
    await Deno.writeFile(outputPath, concated);

    console.info( 'Done \x1b[32m✓\x1b[0m' );
    } )();
    console.info('Done \x1b[32m✓\x1b[0m');
  2. 0b5vr revised this gist Jan 20, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions compeko.js
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,9 @@
    #!/usr/bin/env node

    // compeko - pack JavaScript into a self-extracting html+deflate
    // v1.1.0
    // v1.1.1

    // Copyright (c) 2022 0b5vr
    // Copyright (c) 2022-2023 0b5vr
    // SPDX-License-Identifier: MIT

    // Usage:
  3. 0b5vr revised this gist Jan 20, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion compeko.js
    Original file line number Diff line number Diff line change
    @@ -62,7 +62,7 @@ console.info( 'Compressing the file...' );
    await fs.promises.writeFile( deflatePath, compressed );
    }

    const header = '<svg onload="fetch`#`.then(t=>t.blob()).then(t=>new Response(t.slice(154).stream().pipeThrough(new DecompressionStream`deflate-raw`)).text()).then(eval)">';
    const header = '<svg onload="fetch`#`.then(t=>t.blob()).then(t=>new Response(t.slice(156).stream().pipeThrough(new DecompressionStream('deflate-raw'))).text()).then(eval)">';
    const headerBuffer = Buffer.alloc( header.length );
    headerBuffer.write( header );

  4. 0b5vr revised this gist Aug 22, 2022. 1 changed file with 33 additions and 21 deletions.
    54 changes: 33 additions & 21 deletions compeko.js
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,21 @@
    #!/usr/bin/env node

    // compeko - pack JavaScript into a self-extracting html+deflate
    // v1.1.0

    // Copyright (c) 2022 0b5vr
    // SPDX-License-Identifier: MIT

    // Usage:
    // - prepare a js code, which will be fed into `eval`
    // - install `node-zopfli` as your (dev-) dependency
    // - run: node compeko.js input.js output.html
    // - run: `node compeko.js input.js output.html`

    // Shoutouts to:
    // - gasman, for pnginator ... https://gist.github.com/gasman/2560551
    // - Charles Boccato, for JsExe ... https://www.pouet.net/prod.php?which=59298
    // - subzey, for fetchcrunch ... https://github.com/subzey/fetchcrunch
    // - Achieves almost the same concept. Referred several tricks of the header code

    // =================================================================================================

    @@ -23,6 +26,7 @@ try {
    console.error( e );
    console.error( `
    \x1b[31mMake sure you installed \x1b[35mnode-zopfli\x1b[31m !\x1b[0m` );
    process.exit( 1 );
    }

    if ( process.argv[ 3 ] == null ) {
    @@ -31,36 +35,44 @@ if ( process.argv[ 3 ] == null ) {
    }

    // -- modules --------------------------------------------------------------------------------------
    const { readFileSync, writeFileSync } = require( 'fs' );
    const fs = require( 'fs' );
    const { resolve } = require( 'path' );
    const zopfli = require( 'node-zopfli' );
    const zlib = require( 'zlib' );

    // -- main -----------------------------------------------------------------------------------------
    console.info( 'Compressing the file...' );

    const inputPath = resolve( process.cwd(), process.argv[ 2 ] );
    const outputPath = resolve( process.cwd(), process.argv[ 3 ] );
    ( async () => {
    const inputPath = resolve( process.cwd(), process.argv[ 2 ] );
    const outputPath = resolve( process.cwd(), process.argv[ 3 ] );

    const inputFile = await fs.promises.readFile( inputPath );
    const inputSize = inputFile.length;
    console.info( `Input size: \x1b[32m${ inputSize.toLocaleString() } bytes\x1b[0m` );

    const inputFile = readFileSync( inputPath );
    const inputSize = inputFile.length;
    console.info( `Input size: \x1b[32m${ inputSize.toLocaleString() } bytes\x1b[0m` );
    const compressed = await zopfli.deflate( inputFile, {
    numiterations: 100, // increase this number to shave your last bytes
    blocksplitting: true,
    } );

    const compressed = zopfli.zlibSync( inputFile, {
    numiterations: 100, // increase this number to shave your last bytes
    blocksplitting: true,
    } );
    // extra: output deflate
    {
    const outputPathBase = outputPath.match( /(.*)\..+$/ )[ 1 ];
    const deflatePath = `${ outputPathBase }.deflate.bin`;
    await fs.promises.writeFile( deflatePath, compressed );
    }

    const header = '<script>fetch("#").then(t=>t.blob()).then(t=>new Response(t.slice(156).stream().pipeThrough(new DecompressionStream("deflate"))).text()).then(eval)</script>';
    const headerBuffer = Buffer.alloc( header.length );
    headerBuffer.write( header );
    const header = '<svg onload="fetch`#`.then(t=>t.blob()).then(t=>new Response(t.slice(154).stream().pipeThrough(new DecompressionStream`deflate-raw`)).text()).then(eval)">';
    const headerBuffer = Buffer.alloc( header.length );
    headerBuffer.write( header );

    const concated = Buffer.concat( [ headerBuffer, compressed ] );
    const concated = Buffer.concat( [ headerBuffer, compressed ] );

    const outputSize = concated.length;
    const percentage = ( 100.0 * ( outputSize / inputSize ) ).toFixed( '3' );
    console.info( `Output size: \x1b[32m${ outputSize.toLocaleString() } bytes\x1b[0m (${ percentage } %)` );
    const outputSize = concated.length;
    const percentage = ( 100.0 * ( outputSize / inputSize ) ).toFixed( 3 );
    console.info( `Output size: \x1b[32m${ outputSize.toLocaleString() } bytes\x1b[0m (${ percentage } %)` );

    writeFileSync( outputPath, concated );
    await fs.promises.writeFile( outputPath, concated );

    console.info( 'Done \x1b[32m✓\x1b[0m' );
    console.info( 'Done \x1b[32m✓\x1b[0m' );
    } )();
  5. 0b5vr created this gist Apr 20, 2022.
    66 changes: 66 additions & 0 deletions compeko.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    #!/usr/bin/env node

    // compeko - pack JavaScript into a self-extracting html+deflate

    // Copyright (c) 2022 0b5vr
    // SPDX-License-Identifier: MIT

    // Usage:
    // - prepare a js code, which will be fed into `eval`
    // - install `node-zopfli` as your (dev-) dependency
    // - run: node compeko.js input.js output.html

    // Shoutouts to:
    // - gasman, for pnginator ... https://gist.github.com/gasman/2560551
    // - Charles Boccato, for JsExe ... https://www.pouet.net/prod.php?which=59298

    // =================================================================================================

    // -- sanity check ---------------------------------------------------------------------------------
    try {
    require( 'node-zopfli' );
    } catch ( e ) {
    console.error( e );
    console.error( `
    \x1b[31mMake sure you installed \x1b[35mnode-zopfli\x1b[31m !\x1b[0m` );
    }

    if ( process.argv[ 3 ] == null ) {
    console.error( '\x1b[31mUsage: \x1b[35mnode compeko.js input.js output.html\x1b[0m' );
    process.exit( 1 );
    }

    // -- modules --------------------------------------------------------------------------------------
    const { readFileSync, writeFileSync } = require( 'fs' );
    const { resolve } = require( 'path' );
    const zopfli = require( 'node-zopfli' );
    const zlib = require( 'zlib' );

    // -- main -----------------------------------------------------------------------------------------
    console.info( 'Compressing the file...' );

    const inputPath = resolve( process.cwd(), process.argv[ 2 ] );
    const outputPath = resolve( process.cwd(), process.argv[ 3 ] );

    const inputFile = readFileSync( inputPath );
    const inputSize = inputFile.length;
    console.info( `Input size: \x1b[32m${ inputSize.toLocaleString() } bytes\x1b[0m` );

    const compressed = zopfli.zlibSync( inputFile, {
    numiterations: 100, // increase this number to shave your last bytes
    blocksplitting: true,
    } );

    const header = '<script>fetch("#").then(t=>t.blob()).then(t=>new Response(t.slice(156).stream().pipeThrough(new DecompressionStream("deflate"))).text()).then(eval)</script>';
    const headerBuffer = Buffer.alloc( header.length );
    headerBuffer.write( header );

    const concated = Buffer.concat( [ headerBuffer, compressed ] );

    const outputSize = concated.length;
    const percentage = ( 100.0 * ( outputSize / inputSize ) ).toFixed( '3' );
    console.info( `Output size: \x1b[32m${ outputSize.toLocaleString() } bytes\x1b[0m (${ percentage } %)` );

    writeFileSync( outputPath, concated );

    console.info( 'Done \x1b[32m✓\x1b[0m' );