UNPKG

jspackcompress

Version:

Packing JS into self-extracting HTML file

182 lines (153 loc) 4.45 kB
#!/usr/bin/env node import { createRequire } from "node:module"; import { Command } from "commander"; import { globSync } from "glob"; import { basename, resolve } from "node:path"; import { readFileSync, writeFileSync } from "node:fs"; import { pack } from "../index.js"; const require = createRequire(import.meta.url); const pkg = require("../package.json"); const program = new Command(); console.log(pkg.name, pkg.version); program .name(pkg.name) .description( "Package JavaScript file into self-extracting compressed HTML file" ) .requiredOption( "-i, --input <file>", "JavaScript file to use as the entry point" ) .option( "-o, --output <file>", "output filename for the compressed HTML. If not specified, the input file name with the extension changed from `.js` to `.html` will be used" ) .option( "-l, --level <number>", "compression level (2–9). A lower value is faster but less compressed; a higher value is slower but more compressed", 9 ) .option( "-a, --arg-name <name>", "name of the wrapper function argument to access extra files", "$fs" ) .option( "-g, --getter <type>", "how content of extra files should be returned. Options include: `ArrayBuffer`, `Uint8Array`, `String`, `Blob`, or `BlobURL`. Use `all` to have all types as properties of the wrapper argument", "all" ) .option("-s, --small-decoder", "always use small decoder") .option("-u, --universal-decoder", "use universal decoder") .option("-c, --compact-html", "generate compact HTML") .option( "-e, --extra-head <string>", "additional string to include in the <HEAD> section" ) .option( "-b, --extra-body <string>", "additional string to include in the <BODY> section" ) .argument("[extra files...]") .version(pkg.version); program .addHelpText( "after", ` You can use glob patterns to specify extra files: $ ${pkg.name} -i index.js -o game.html assets/* ` ) .parse(); let filesContent = {}; const opts = program.opts(); let script; try { script = readFileSync(opts.input, "utf8"); } catch (e) { console.error(`Can't read file: "${opts.input}"\n ${e.message}`); process.exit(1); } console.log(""); for (let file of program.args) { let globs = globSync(file, { nodir: true, posix: true, windowsPathsNoEscape: true, }); if (globs.length === 0) { console.error(`Can't find file: "${file}".`); process.exit(1); } globs.forEach((g) => { let content; try { content = readFileSync(g); } catch (e) { console.error(`Can't read file: "${g}"\n ${e.message}`); process.exit(1); } let fName = basename(resolve(g)); if (filesContent[fName]) { console.warn( ` Duplicate file "${fName}".\n Replacing "${filesContent[fName].location}" with content from "${g}".` ); } else { console.log(` Added "${fName}" from "${g}".`); } filesContent[fName] = { content, location: g, }; }); } let startTime = performance.now(); let result = await pack({ script, compressionlevel: opts.level, argName: opts.argName, accessType: opts.getter, useSmallDecoder: opts.smallDecoder, compactHtml: opts.compactHtml, universalDecoder: opts.universalDecoder, extraHead: opts.extraHead, extraBody: opts.extraBody, files: filesContent, }); let endTime = performance.now(); let st = result.stats; let outFile = opts.output; if (!outFile) { outFile = opts.input.replace(/\.js$/i, "") + ".html"; } try { writeFileSync(outFile, result.payload); } catch (e) { console.error(`Can't write to file: "${outFile}"\n ${e.message}`); process.exit(1); } console.log(`\nPacked in ${((endTime - startTime) / 1000).toFixed(2)}s\n`); console.log(` Payload size: ${st.origSize}`); console.log( ` Compressed size: ${st.cmpSize} (${( (100 * st.cmpSize) / st.origSize ).toFixed(2)}%)` ); console.log( ` Escaped size: ${st.escSize} (${((100 * st.escSize) / st.cmpSize).toFixed( 2 )}% / +${st.escSize - st.cmpSize})` ); console.log( ` HTML file size: ${result.payload.length} (${( (100 * result.payload.length) / st.escSize ).toFixed(2)}% / +${result.payload.length - st.escSize})` ); console.log( ` Total overhead: ${result.payload.length - st.cmpSize} (${( (100 * (result.payload.length - st.cmpSize)) / result.payload.length ).toFixed(2)}%)` );