From f544dbd9ea7e02da2e1eae8aa69344a89d1111cb Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Sun, 25 Nov 2018 19:59:27 +0200 Subject: [PATCH] CLI usage updates (#53) * cli usage updates * implement run * implement render output, flatten asset output --- readme.md | 4 ++- src/cli.js | 100 ++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/readme.md b/readme.md index ef57d83a..663b9384 100644 --- a/readme.md +++ b/readme.md @@ -22,9 +22,11 @@ together with all its dependencies, gcc-style. ### CLI ```bash -$ ncc input.js -o bundle.js +$ ncc build input.js -o dist ``` +Outputs the build of `input.js` into `dist/index.js`. + ### Node.js ```js diff --git a/src/cli.js b/src/cli.js index 5d5ece9a..4440c8ee 100755 --- a/src/cli.js +++ b/src/cli.js @@ -1,26 +1,67 @@ -const { resolve } = require("path"); +const { resolve, relative, dirname, sep } = require("path"); const args = require("arg")({ - "--help": Boolean, - "-h": "--help", "--external": [String], "-e": "--external", "--out": String, "-o": "--out", "--no-minify": Boolean, - M: "--no-minify" + M: "--no-minify", + "--quiet": Boolean, + "-q": "--quiet" }); -const usage = `ncc build [opts] +const usage = `Usage: ncc + +Commands: + build [opts] + run [opts] + help + version + Options: + -o, --out [file] Output directory for build (defaults to dist) -M, --no-minify Skip output minification -e, --external [mod] Skip bundling 'mod'. Can be used many times - -o, --out [file] Output directory (defaults to dist) - -h, --help Show help + -q, --quiet Disable build summaries / non-error outputs `; -if (args["--help"]) { - console.error(usage); - process.exit(2); +function renderSummary (code, assets, outDir, buildTime) { + if (!outDir.endsWith(sep)) + outDir += sep; + const codeSize = Math.round(Buffer.byteLength(code, 'utf8') / 1024); + const assetSizes = Object.create(null); + let maxSize = codeSize; + let maxAssetNameLength = 8; // "index.js".length + for (const asset of Object.keys(assets)) { + const assetSource = assets[asset]; + const assetSize = Math.round((assetSource.byteLength || Buffer.byteLength(assetSource, 'utf8')) / 1024); + assetSizes[asset] = assetSize; + if (assetSize > maxSize) + maxSize = assetSize; + if (asset.length > maxAssetNameLength) + maxAssetNameLength = asset.length; + } + const orderedAssets = Object.keys(assets).sort((a, b) => assetSizes[a] > assetSizes[b] ? 1 : -1); + + const sizePadding = maxSize.toString().length; + + const indexRender = `${codeSize.toString().padStart(sizePadding, ' ')}kB ${outDir}${'index.js'.padEnd(maxAssetNameLength, ' ')} [${buildTime}ms]\n`; + + let output = "", first = true; + for (const asset of orderedAssets) { + if (first) + first = false; + else + output += "\n"; + if (codeSize < assetSizes[asset]) + output += indexRender; + output += `${assetSizes[asset].toString().padStart(sizePadding, ' ')}kB ${outDir}${asset}` + } + + if (maxSize === codeSize) + output += (first ? "" : "\n") + indexRender; + + return output; } if (args._.length === 0) { @@ -28,31 +69,64 @@ if (args._.length === 0) { process.exit(1); } +let run = false; +let outDir = args["--out"]; + switch (args._[0]) { + case "run": + if (args._.length > 2) { + console.error(`Error: Too many run arguments provided\n${usage}`); + process.exit(1); + } + if (args["--out"]) { + console.error(`Error: --out flag is not compatible with ncc run\n${usage}`); + process.exit(1); + } + outDir = resolve(require("os").tmpdir(), Math.random().toString(16).substr(2)); + run = true; + + // fallthrough case "build": if (args._.length > 2) { console.error(`Error: Too many build arguments provided\n${usage}`); process.exit(1); } - const ncc = require("./index.js")(resolve(args._[1] || "."), { + const startTime = Date.now(); + const ncc = require("./index.js")(eval("require.resolve")(resolve(args._[1] || ".")), { minify: !args["--no-minify"], externals: args["--external"] }); ncc.then(({ code, assets }) => { - const outDir = args["--out"] || resolve("dist"); + outDir = outDir || resolve("dist"); const fs = require("fs"); const mkdirp = require("mkdirp"); mkdirp.sync(outDir); fs.writeFileSync(outDir + "/index.js", code); for (const asset of Object.keys(assets)) { - mkdirp.sync(path.dirname(asset)); + mkdirp.sync(dirname(asset)); fs.writeFileSync(outDir + "/" + asset, assets[asset]); } + + if (!args['--quiet']) + console.log(renderSummary(code, assets, run ? '' : relative(process.cwd(), outDir), Date.now() - startTime)); + + if (run) { + const ps = require("child_process").fork(outDir + "/index.js"); + ps.on("close", () => require("rimraf").sync(outDir)); + } }); break; + case "help": + console.error(usage); + process.exit(2); + + case "version": + console.log(require('../package.json').version); + break; + default: console.error(`Error: Invalid command "${args._[0]}"\n${usage}`); process.exit(1);