-
-
Save developit/4cba2e9ec7d1e09b8245febe7bad82bd to your computer and use it in GitHub Desktop.
Revisions
-
developit revised this gist
Jun 5, 2024 . 1 changed file with 10 additions and 70 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #!/usr/bin/env node /* eslint-disable no-param-reassign, no-fallthrough, guard-for-in, require-atomic-updates */ const path = require('node:path'); const {Worker} = require('node:worker_threads'); @@ -261,8 +261,6 @@ parentPort.once('message', ([mod, filename, args, env, compiledCode]) => { module.id = basename(filename); module.filename = __filename = filename; module.path = __dirname = dirname(__filename); Object.assign(process.env, env); parentPort.postMessage(0); const exit = process.exit.bind(process); @@ -282,7 +280,6 @@ const workerPool = { create: () => new Worker(workerShim, {eval: true}), }; workerPool.workers.push(workerPool.create()); const pkgCache = new Map(); function getPkg(filename) { @@ -313,72 +310,14 @@ async function runNode(script, args, env, compiledCode) { filename.endsWith('.mjs') || ((await getPkg(filename)).type === 'module' && !filename.endsWith('.cjs')); return new Promise((resolve) => { const end = done.submeasure('worker start'); const worker = workerPool.get(); worker.postMessage([isModule, filename, args, $env(env), compiledCode]); worker.once('message', done.submeasure('worker init')); worker.once('exit', done); worker.once('exit', resolve); end(); }); } @@ -503,12 +442,13 @@ async function runScript(scriptName, args, env) { } (async () => { const start = performance.now(); const cmd = path.basename(process.argv[1]); const runner = cmd === 'exec' ? runBin : runScript; const name = process.argv[2]; if (!name) panic('No script name provided.'); try { process.exitCode = await runner(name, process.argv.slice(3)); } finally { let worker; while ((worker = workerPool.workers?.pop())) worker.terminate(); -
developit revised this gist
Jun 5, 2024 . 1 changed file with 153 additions and 41 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,14 +1,5 @@ #!/usr/bin/env node /* eslint-disable no-param-reassign, no-fallthrough, guard-for-in */ const path = require('node:path'); const {Worker} = require('node:worker_threads'); @@ -22,6 +13,11 @@ if (debugEnv) { } } const readFile = (file) => require('node:fs/promises').readFile(file, 'utf-8'); const exists = (filename) => require('node:fs/promises') .access(filename) .then(() => true) .catch(() => false); const $env = (env) => (env ? {...process.env, ...env} : process.env); @@ -98,6 +94,12 @@ function parseShell(script) { context = ARGS; } } else if (context === ARGS) { // unquote if (buf[0] === "'" && buf.at(-1) === "'") { buf = buf.slice(1, -1); } else if (buf[0] === '"' && buf.at(-1) === '"') { buf = buf.slice(1, -1).replaceAll('\\"', '"'); } command.args.push(buf); } buf = ''; @@ -134,6 +136,10 @@ function parseShell(script) { } break; case 'if': if (context !== INITIAL) { buf += op; continue; } logic.push({ type: 'conditional', test: [], @@ -145,16 +151,28 @@ function parseShell(script) { context = INITIAL; break; case 'then': if (context !== INITIAL) { buf += op; continue; } seq = logic.at(-1)?.consequent; command = null; context = INITIAL; break; case 'else': if (context !== INITIAL) { buf += op; continue; } seq = logic.at(-1)?.alternate; command = null; context = INITIAL; break; case 'fi': if (context !== INITIAL) { buf += op; continue; } seq = root; if (logic.length) seq.push(logic.pop()); break; @@ -235,21 +253,36 @@ async function run(seq, env = {}) { } const workerShim = ` const {parentPort} = require('node:worker_threads'); const {dirname, basename, sep} = require('path'); parentPort.once('message', ([mod, filename, args, env, compiledCode]) => { process.stdout.isTTY = process.stdin.isTTY = process.stderr.isTTY = true; process.argv = [process.argv[0], filename].concat(args); module.id = basename(filename); module.filename = __filename = filename; module.path = __dirname = dirname(__filename); // let p = ''; // module.paths = module.path.split(sep).map((seg) => (p += seg + sep) + 'node_modules').reverse(); Object.assign(process.env, env); parentPort.postMessage(0); const exit = process.exit.bind(process); process.exit = (exitCode) => { process.stdout.end(); process.setUncaughtExceptionCaptureCallback(() => {}); setTimeout(exit, 0, exitCode); }; if (mod && !compiledCode) return import(filename); require = require('node:module').createRequire(require.resolve(filename)); require('vm').runInThisContext(compiledCode || require('fs').readFileSync(filename, 'utf-8'), {filename}); }); `; const workerPool = { workers: [], get: () => workerPool.workers.pop() ?? workerPool.create(), create: () => new Worker(workerShim, {eval: true}), }; workerPool.workers.push(workerPool.create()); // if (process.env.POOL) workerPool.workers.push(workerPool.create()); const pkgCache = new Map(); function getPkg(filename) { @@ -265,6 +298,13 @@ function getPkg(filename) { } async function runNode(script, args, env, compiledCode) { if ( process.env.ESBUILD === 'force' && compiledCode === undefined && !script.endsWith('.built.mjs') ) { return runTs(script, args, env); } const scriptId = `node(${script} ${args.join(' ')})`; const done = measure(scriptId); const filename = path.resolve(script); @@ -275,28 +315,66 @@ async function runNode(script, args, env, compiledCode) { return new Promise((resolve, reject) => { const end = done.submeasure('worker start'); /* let worker; if (process.env.POOL) { worker = workerPool.get(); worker.postMessage([isModule, filename, args, $env(env), compiledCode]); } else { const scriptStr = JSON.stringify(filename); const shim = `{ console.log(process.argv.slice()); process.argv[1] = ${scriptStr}; ${ // eslint-disable-next-line no-nested-ternary compiledCode ? `require('vm').runInThisContext(${JSON.stringify( compiledCode, )}, {filename: ${scriptStr}});` : isModule ? `import(${scriptStr});` : `require('vm').runInThisContext(require('fs').readFileSync(${scriptStr}, 'utf-8'), {filename: ${scriptStr}});` } }`; // const shim = // compiledCode || (isModule && `import(${JSON.stringify(filename)});`); // worker = new Worker(shim || filename, { worker = new Worker(shim, { env: $env(env), argv: args, eval: true, // eval: Boolean(shim), // resourceLimits: { // maxOldGenerationSizeMb: 9000, // maxYoungGenerationSizeMb: 9000, // }, }); } */ const worker = workerPool.get(); worker.postMessage([isModule, filename, args, $env(env), compiledCode]); end(); worker.once('message', done.submeasure('worker init')); // worker.once('online', done.submeasure('worker init')); // worker.on('error', (err) => { // let stack = err.stack; // try { // const ref = err.stack?.match(/^\s*at .*?\((\/[^)]*?):(\d+):(\d+)\)?$/m); // if (ref) { // const [, file, lineNo, colNo] = ref; // const code = require('node:fs').readFileSync(file, 'utf-8'); // const loc = `${file}:${lineNo}:${colNo}`; // const line = code.split('\n')[lineNo - 1]; // stack = `\n on ${loc}:\n ${line}\n ${'-'.repeat(colNo | 0)}^`; // } // } catch (_) { // // ignore, use native stack // } // console.error(red(`${bold('Error')}: ${err}${dim(stack)}`)); // done(); // reject(err); // }); worker.once('exit', (exitCode) => { done(); resolve(exitCode); @@ -307,20 +385,43 @@ async function runNode(script, args, env, compiledCode) { async function runTs(script, args, env) { const end = measure(`esbuild(${script})`); const {build} = require('esbuild'); const outfile = script.endsWith('.mjs') ? script.replace(/([^/]+)\.mjs$/, '.$1.built.mjs') : undefined; if (!outfile && !/\.[a-z]+$/.test(script)) { const [ext, index] = await Promise.all([ exists(`${script}.ts`), exists(`${script}/index.ts`), ]); if (ext) script += '.ts'; else if (index) script += '/index.ts'; } const result = await build({ bundle: true, entryPoints: [script], target: 'node20', platform: 'node', format: outfile ? 'esm' : 'cjs', packages: 'external', write: Boolean(outfile), outfile, treeShaking: true, minifyIdentifiers: true, minifySyntax: true, nodePaths: [], }); if (result.errors.length) { panic(`TS build of ${script} failed:\n${result.errors.join('\n')}`); } if (outfile) { end(); try { return await runNode(outfile, args, env); } finally { require('node:fs').unlink(outfile, Object); } } let code = result.outputFiles[0].text; // move top-level requires to callsites so they only get evaluated when surrounding code is executed @@ -354,12 +455,14 @@ async function runBin(bin, args, env) { if (Object.prototype.hasOwnProperty.call(BIN, bin)) { return BIN[bin](args, env); } let resolvedBin = bin; try { const done = measure(`resolve-bin(${bin} ${args.join(' ')})`); const code = await readFile(`node_modules/.bin/${bin}`); resolvedBin = `node_modules/.bin/${bin}`; // exec node "$basedir/../vite/bin/vite.js" "$@" const match = code.match(/exec +node +"([^"]+)" +"\$@"/)?.[1]; if (!match) throw Error(`Unknown format at node_modules/.bin/${bin}`); const binFile = path.resolve( match.replace('$basedir', './node_modules/.bin'), ); @@ -368,19 +471,28 @@ async function runBin(bin, args, env) { return runNode(binRel, args, env); } catch (err) { const done = measure(`run-bin(${bin} ${args.join(' ')})`); // console.error(`failed to run "${bin}" seamlessly:`, err); return new Promise((resolve) => { const {spawn} = require('node:child_process'); const proc = spawn(resolvedBin, args, {env: $env(env), stdio: 'inherit'}); // proc.on('error', reject); proc.once('exit', (exitCode) => { done(); resolve(exitCode); }); }); } } async function runScript(scriptName, args, env) { const script = (await pkgPromise).scripts[scriptName]; if (!script) { const bin = path.basename(scriptName); if (await exists(`node_modules/.bin/${bin}`)) { return runBin(bin, args, env); } panic(`Unknown script "${scriptName}".`); } let scriptWithArgs = script; for (const arg of args) scriptWithArgs += ` ${arg}`; const done = measure('parse'); -
developit revised this gist
May 31, 2024 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,7 +4,7 @@ * run: run npm scripts faster and with fewer resources than should be possible. * Parses and executes in-process instead of spawning nested node+sh processes. Why: * - npm scripts that run other npm scripts have no overhead * - npm scripts that use ts-node get prebundled and cached by esbuild instead of using ts-node * Usage: * ./run my-script-name --a=b */ -
developit revised this gist
May 31, 2024 . 1 changed file with 1 addition and 33 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -275,35 +275,6 @@ async function runNode(script, args, env, compiledCode) { return new Promise((resolve, reject) => { const end = done.submeasure('worker start'); const worker = workerPool.get(); worker.postMessage([isModule, filename, args, $env(env), compiledCode]); end(); @@ -402,10 +373,7 @@ async function runBin(bin, args, env) { const {spawn} = require('node:child_process'); const proc = spawn(bin, args, {env: $env(env), stdio: 'inherit'}); // proc.on('error', reject); proc.once('exit', (exitCode) => done(resolve(exitCode))); }); } } -
developit revised this gist
May 31, 2024 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,7 +2,9 @@ /** * run: run npm scripts faster and with fewer resources than should be possible. * Parses and executes in-process instead of spawning nested node+sh processes. Why: * - npm scripts that run other npm scripts have no overhead * - npm scripts that use ts-node get prebundled and cached by esbuild * Usage: * ./run my-script-name --a=b */ -
developit revised this gist
May 31, 2024 . 2 changed files with 24 additions and 570 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,9 +1,15 @@ #!/usr/bin/env node /** * run: run npm scripts faster and with fewer resources than should be possible. * Parses and executes in-process instead of spawning nested node+sh processes. * Usage: * ./run my-script-name --a=b */ /* eslint-disable no-param-reassign, no-fallthrough, guard-for-in */ const path = require('node:path'); const {Worker} = require('node:worker_threads'); const DEBUG = {parsing: false, timing: false}; const debugEnv = process.env.DEBUG; @@ -15,10 +21,6 @@ if (debugEnv) { } const readFile = (file) => require('node:fs/promises').readFile(file, 'utf-8'); const $env = (env) => (env ? {...process.env, ...env} : process.env); let markId = 0; @@ -65,26 +67,24 @@ const COMMAND = 1; const ARGS = 2; function parseShell(script) { script += ' '; const tokenizer = /(if|then|fi|&&|\|\||[ ;"'`()=])/g; const expectedOps = { ')': '(', fi: 'if', }; const stack = []; const logic = []; let context = INITIAL; let token; let index = 0; let lastOp; let lastEnv; let buf = ''; let command = {name: '', args: [], env: {}}; const root = []; let seq = root; const commit = () => { if (context === INITIAL) { if (lastEnv) { if (!command) seq.push((command = {name: '', args: [], env: {}})); @@ -102,7 +102,6 @@ function parseShell(script) { }; while ((token = tokenizer.exec(script))) { let op = token[0]; buf += script.substring(index, token.index); index = tokenizer.lastIndex; switch (op) { @@ -111,14 +110,12 @@ function parseShell(script) { if (lastOp) continue; seq.push({type: op}); case ';': if (lastOp) continue; commit(); command = null; context = INITIAL; break; case ' ': if (!buf) continue; if (lastOp) { if (buf) buf += ' '; @@ -142,19 +139,16 @@ function parseShell(script) { alternate: [], }); seq = logic.at(-1)?.test; command = null; context = INITIAL; break; case 'then': seq = logic.at(-1)?.consequent; command = null; context = INITIAL; break; case 'else': seq = logic.at(-1)?.alternate; command = null; context = INITIAL; break; @@ -169,15 +163,9 @@ function parseShell(script) { case '`': buf += op; default: if (op in expectedOps) { const start = expectedOps[op]; if (lastOp !== start) { const line = `${script}\n${'-'.repeat(token.index)}^`; panic(`unexpected "${op}"\n${dim(line)}`); } @@ -189,7 +177,6 @@ function parseShell(script) { } else { stack.push(op); lastOp = op; } break; } @@ -211,10 +198,8 @@ async function run(seq, env = {}) { case 'conditional': if (await run(node.test, env)) { prev = await run(node.consequent, env); } else if (node.alternate) { prev = await run(node.alternate, env); } break; default: @@ -277,10 +262,7 @@ function getPkg(filename) { return prom; } async function runNode(script, args, env, compiledCode) { const scriptId = `node(${script} ${args.join(' ')})`; const done = measure(scriptId); const filename = path.resolve(script); @@ -290,124 +272,9 @@ async function runNode(script, args, env, compiledCode, hash) { ((await getPkg(filename)).type === 'module' && !filename.endsWith('.cjs')); return new Promise((resolve, reject) => { const end = done.submeasure('worker start'); // if (process.env.POOL) { // worker = workerPool.get(); // worker.postMessage([isModule, filename, args, $env(env), compiledCode]); // } else { @@ -495,25 +362,22 @@ async function runTs(script, args, env) { ); end(); // process.setSourceMapsEnabled(true); return runNode(script, args, env, code); } const BIN = { 'ts-node': (args, env) => { let script; const remainingArgs = args.filter((arg) => { if (arg[0] === '-' || script) return true; script = arg; return false; }); return runTs(script, remainingArgs, env); }, }; async function runBin(bin, args, env) { if (Object.prototype.hasOwnProperty.call(BIN, bin)) { return BIN[bin](args, env); } @@ -553,16 +417,10 @@ async function runScript(scriptName, args, env) { const parsed = parseShell(scriptWithArgs); if (DEBUG.parsing) console.log('parsed: ', scriptWithArgs, parsed); done(); return run(parsed, env); } (async () => { const script = process.argv[2]; if (!script) panic('No script name provided.'); const start = performance.now(); @@ -582,205 +440,3 @@ async function runScript(scriptName, args, env) { } } })(); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,202 +0,0 @@ -
developit created this gist
May 31, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,786 @@ #!/usr/bin/env node /* eslint-disable no-param-reassign, no-fallthrough, guard-for-in, no-nested-ternary */ const {Worker} = require('node:worker_threads'); const path = require('node:path'); const DEBUG = {parsing: false, timing: false}; const debugEnv = process.env.DEBUG; if (debugEnv) { for (const name in DEBUG) { DEBUG[name] = debugEnv === 'true' || debugEnv === '1' || debugEnv.includes(name); } } const readFile = (file) => require('node:fs/promises').readFile(file, 'utf-8'); // process.env.NODE_OPTIONS = `--no-addons --no-deprecation --no-force-async-hooks-checks --no-global-search-paths ${ // process.env.NODE_OPTIONS || '' // }`; const $env = (env) => (env ? {...process.env, ...env} : process.env); let markId = 0; function measure(name, parent = '', depth = 0) { const start = `${parent}:${name}:${++markId}`; performance.mark(start); function end() { performance.measure(name, { start, detail: {depth, parent}, }); } end.submeasure = (sub) => measure(sub, start, depth + 1); return end; } const color = (code, end) => (str) => `\x1B[${code}m${str}\x1B[${end}m`; const bold = color(1, 22); const dim = color(2, 22); const red = color(31, 39); const panic = (message) => { console.log(red(bold('Error: ') + message)); process.exit(1); }; function json5(json) { try { return JSON.parse(json); } catch (_2) { return (0, eval)(`(${json})`); } } const endPkgParse = measure('parse package.json'); let pkg; const pkgPromise = readFile('package.json').then((json) => { pkg = json5(json); endPkgParse(); return pkg; }); const INITIAL = 0; const COMMAND = 1; const ARGS = 2; function parseShell(script) { const tokenizer = /(if|then|fi|&&|\|\||[ ;"'`()=])/g; script += ' '; let token; let index = 0; const stack = []; const logic = []; let lastOp; let context = INITIAL; let lastEnv; let buf = ''; let command = {name: '', args: [], env: {}}; const root = []; let seq = root; const expectedOps = { ')': '(', // then: 'if', fi: 'if', }; const commit = () => { // console.log({context, buf, lastEnv}); if (context === INITIAL) { if (lastEnv) { if (!command) seq.push((command = {name: '', args: [], env: {}})); command.env[lastEnv] = buf; lastEnv = undefined; } else if (buf) { if (!command) seq.push((command = {name: '', args: [], env: {}})); command.name = buf; context = ARGS; } } else if (context === ARGS) { command.args.push(buf); } buf = ''; }; while ((token = tokenizer.exec(script))) { let op = token[0]; // console.log(token); buf += script.substring(index, token.index); index = tokenizer.lastIndex; switch (op) { case '&&': case '||': if (lastOp) continue; seq.push({type: op}); case ';': // if (lastOp === 'if') continue; if (lastOp) continue; commit(); command = null; context = INITIAL; break; case ' ': // console.log('space', {context, buf, lastOp, lastEnv}); if (!buf) continue; if (lastOp) { if (buf) buf += ' '; continue; } commit(); break; case '=': if (context === INITIAL && !lastOp) { lastEnv = buf; buf = ''; } else { buf += op; } break; case 'if': logic.push({ type: 'conditional', test: [], consequent: [], alternate: [], }); seq = logic.at(-1)?.test; // seq.push((command = {name: '', args: [], env: {}})); command = null; context = INITIAL; break; case 'then': seq = logic.at(-1)?.consequent; // seq.push((command = {name: '', args: [], env: {}})); command = null; context = INITIAL; break; case 'else': seq = logic.at(-1)?.alternate; // seq.push((command = {name: '', args: [], env: {}})); command = null; context = INITIAL; break; case 'fi': seq = root; if (logic.length) seq.push(logic.pop()); break; case '(': case ')': case '"': case `'`: case '`': buf += op; default: // if (op === 'then') { // seq.push({type: 'if'}); // seq.push((command = {name: '', args: [], env: {}})); // continue; // } if (op in expectedOps) { const start = expectedOps[op]; if (lastOp !== start) { // console.log({context, stack, buf, op, start, lastOp, seq}); const line = `${script}\n${'-'.repeat(token.index)}^`; panic(`unexpected "${op}"\n${dim(line)}`); } op = start; } if (lastOp === op) { stack.pop(); lastOp = stack.at(-1); } else { stack.push(op); lastOp = op; // continue; } break; } } if (command && seq.at(-1) !== command) seq.push(command); return seq; } async function run(seq, env = {}) { let prev = true; for (const node of seq) { switch (node.type) { case '&&': if (!prev) return; break; case '||': if (prev) return prev; break; case 'conditional': if (await run(node.test, env)) { prev = await run(node.consequent, env); // await run(node.consequent, env); } else if (node.alternate) { prev = await run(node.alternate, env); // await run(node.alternate, env); } break; default: if (node.name === '$npm_execpath' || node.name === 'npm') { let script = node.args.shift(); if (script === 'run') script = node.args.shift(); prev = await runScript(script, node.args, {...env, ...node.env}); } else if (node.name === 'node') { const script = node.args.shift(); prev = await runNode(script, node.args, {...env, ...node.env}); } else if (node.name === 'test') { const a1 = node.args[0].replace( /$([a-z0-9_]+)/g, (_, c) => process.env[c] ?? _, ); const a2 = node.args[2].replace( /$([a-z0-9_]+)/g, (_, c) => process.env[c] ?? _, ); if (node.args[1] === '=') prev = a1 === a2; else if (node.args[1] === '!=') prev = a1 !== a2; } else if (node.name) { // panic(`Unknown command ${node.name} (${node.args})`); prev = await runBin(node.name, node.args, node.env); } else { panic(`Unknown node ${JSON.stringify(node)}`); } } } return prev; } const workerShim = ` require('worker_threads').parentPort.once('message', ([mod, filename, args, env, compiledCode]) => { process.argv.splice(2, process.argv.length, ...args); Object.assign(process.env, env); require('worker_threads').parentPort.postMessage('done'); if (mod && !compiledCode) return import(filename); const code = compiledCode || require('fs').readFileSync(filename, 'utf-8'); require('vm').runInThisContext(code, {filename}); }); `; const workerPool = { workers: [], get: () => workerPool.workers.pop() ?? workerPool.create(), create: () => new Worker(workerShim, {eval: true}), }; if (!process.env.INLINE) workerPool.workers.push(workerPool.create()); const pkgCache = new Map(); function getPkg(filename) { const index = filename.lastIndexOf('/node_modules/'); if (index === -1) return pkgPromise; const pkgName = filename.slice(index + 14).match(/^(@[^/]+\/)?[^/]+/g)[0]; const pkgFile = `${filename.slice(0, index + 14)}${pkgName}/package.json`; const cached = pkgCache.get(pkgFile); if (cached) return cached; const prom = readFile(pkgFile).then(json5); pkgCache.set(pkgFile, prom); return prom; } async function runNode(script, args, env, compiledCode, hash) { // if (process.env.FORCE_ESBUILD && compiledCode === undefined) { // return runTs(script, args, env); // } const scriptId = `node(${script} ${args.join(' ')})`; const done = measure(scriptId); const filename = path.resolve(script); const isModule = filename.endsWith('.mjs') || ((await getPkg(filename)).type === 'module' && !filename.endsWith('.cjs')); return new Promise((resolve, reject) => { // if (process.env.FORK) { // const {fork} = require('node:child_process'); // return fork(script, args, {env, stdio: 'inherit'}) // .once('error', reject) // .once('exit', resolve); // } const end = done.submeasure('worker start'); // let worker; if (process.env.INLINE) { /** @type {typeof process} */ const processShim = { ...process, argv: [process.argv[0], filename, ...args], exitCode: 0, exit(code) { processShim.exitCode = code; done(); resolve(processShim.exitCode); }, }; const _import = async (id) => { const oldArgv = process.argv; const oldExit = process.exit; process.argv = processShim.argv; process.exit = processShim.exit; try { return await import(id); } finally { process.argv = oldArgv; process.exit = oldExit; } }; const _require = (id) => { if (id === 'process' || id === 'node:process') return processShim; return require(id); }; // if (process.env.LAZYREQUIRE) { // const {builtinModules} = require('node:module'); // const requireCache = new Map(); // const dlv = (obj, keyPath) => { // for (const key of keyPath) obj = obj?.[key]; // return obj; // }; // const _export = (root, keyPath) => // dlv(root, keyPath) ?? dlv(root.default, keyPath); // const recursiveProxy = (load, loaded, keyPath = []) => // new Proxy(function () {}, { // get(target, key) { // if (key === '__esModule' && !keyPath.length) return false; // if (key === Symbol.toPrimitive || loaded()) { // return () => _export(load(), keyPath); // } // return recursiveProxy(load, loaded, keyPath.concat(key)); // }, // set(target, key, value) { // _export(load(), keyPath)[key] = value; // }, // apply(target, context, args) { // return _export(load(), keyPath).apply(context, args); // }, // construct(target, args, newTarget) { // return Reflect.construct( // _export(load(), keyPath), // args, // newTarget, // ); // }, // }); // _require = (id) => { // const node = id.replace('node:', ''); // if (node === 'process') return processShim; // if (builtinModules.includes(node)) return require(node); // const cached = requireCache.get(id); // if (cached) return cached; // let loaded = false; // let mod; // const getMod = () => // loaded ? mod : ((loaded = true), (mod = require(id))); // return recursiveProxy(getMod, () => loaded); // }; // } const _eval = (code) => { return require('node:vm').runInNewContext( code, { ...global, require: _require, process: processShim, }, {filename}, ); // const {Script} = require('node:vm'); // const script = new Script(code, { // filename, // cachedData: hash && cacheStore?.get(filename, hash), // produceCachedData: Boolean(hash), // }); // if (hash) cacheStore?.set(filename, hash, script.cachedData); // return script.runInNewContext({ // ...global, // require: _require, // process: processShim, // }); }; const prom = compiledCode ? Promise.resolve(compiledCode).then(_eval) : isModule ? _import(filename) : readFile(filename).then(_eval); return prom.catch(console.error).then(end); } // } else if (process.env.POOL) { // worker = workerPool.get(); // worker.postMessage([isModule, filename, args, $env(env), compiledCode]); // } else { // const scriptStr = JSON.stringify(filename); // const shim = `{ // process.argv[1] = ${scriptStr}; // ${ // compiledCode // ? `require('vm').runInThisContext(${JSON.stringify( // compiledCode, // )}, {filename: ${scriptStr}});` // : isModule // ? `import(${scriptStr});` // : `require('vm').runInThisContext(require('fs').readFileSync(${scriptStr}, 'utf-8'), {filename: ${scriptStr}});` // } // require('worker_threads').parentPort.postMessage(0); // }`; // worker = new Worker(shim, { // env: $env(env), // argv: args, // eval: true, // // resourceLimits: { // // maxOldGenerationSizeMb: 9000, // // maxYoungGenerationSizeMb: 9000, // // }, // }); // } const worker = workerPool.get(); worker.postMessage([isModule, filename, args, $env(env), compiledCode]); end(); worker.once('message', done.submeasure('worker init')); worker.on('error', (err) => { let stack = err.stack; try { const ref = err.stack?.match(/^\s*at .*?\((\/[^)]*?):(\d+):(\d+)\)?$/m); if (ref) { const [, file, lineNo, colNo] = ref; const code = require('node:fs').readFileSync(file, 'utf-8'); const loc = `${file}:${lineNo}:${colNo}`; const line = code.split('\n')[lineNo - 1]; stack = `\n on ${loc}:\n ${line}\n ${'-'.repeat(colNo | 0)}^`; } } catch (_) { // ignore, use native stack } console.error(red(`${bold('Error')}: ${err}${dim(stack)}`)); done(); reject(err); }); worker.once('exit', (exitCode) => { done(); resolve(exitCode); }); }); } async function runTs(script, args, env) { const end = measure(`esbuild(${script})`); const {build} = require('esbuild'); const result = await build({ bundle: true, entryPoints: [script], target: 'node20', platform: 'node', format: 'cjs', packages: 'external', write: false, treeShaking: true, nodePaths: [], }); if (result.errors.length) { panic(`TS build of ${script} failed:\n${result.errors.join('\n')}`); } let code = result.outputFiles[0].text; // move top-level requires to callsites so they only get evaluated when surrounding code is executed const idents = {}; code = code.replace( /(?:^var (import_[a-zA-Z0-9_$]+) = ((?:__toESM\()?require\("[^"]+"\)\)?);?$|\b(import_[a-zA-Z0-9_$]+)\b)/gm, (_, ident, req, ident2) => { if (ident2) return idents[ident2] ?? ident2; idents[ident] = req; return ''; }, ); end(); // process.setSourceMapsEnabled(true); return runNode(script, args, env, code, result.outputFiles[0].hash); } const BIN = { 'ts-node': function (args, env) { let script; const remainingArgs = args.filter((arg) => { if (arg[0] !== '-' && !script) { script = arg; return false; } return true; }); return runTs(script, remainingArgs, env); }, }; async function runBin(bin, args, env) { // console.log('RUN BIN', {bin, args, env}); if (Object.prototype.hasOwnProperty.call(BIN, bin)) { return BIN[bin](args, env); } try { const done = measure(`resolve-bin(${bin} ${args.join(' ')})`); const code = await readFile(`node_modules/.bin/${bin}`); // exec node "$basedir/../vite/bin/vite.js" "$@" const match = code.match(/exec node +"([^"]+)" "\$@"/)[1]; if (!match) panic(`Unknown format at node_modules/.bin/${bin}`); const binFile = path.resolve( match.replace('$basedir', './node_modules/.bin'), ); const binRel = path.relative('.', binFile); done(); return runNode(binRel, args, env); } catch (err) { const done = measure(`run-bin(${bin} ${args.join(' ')})`); console.error(`failed to run "${bin}" seamlessly:`, err); return new Promise((resolve) => { const {spawn} = require('node:child_process'); const proc = spawn(bin, args, {env: $env(env), stdio: 'inherit'}); // proc.on('error', reject); proc.once('exit', (exitCode) => { done(); resolve(exitCode); }); }); } } async function runScript(scriptName, args, env) { const script = (await pkgPromise).scripts[scriptName]; if (!script) panic(`Unknown script "${scriptName}".`); let scriptWithArgs = script; for (const arg of args) scriptWithArgs += ` ${arg}`; const done = measure('parse'); const parsed = parseShell(scriptWithArgs); if (DEBUG.parsing) console.log('parsed: ', scriptWithArgs, parsed); done(); // console.log('RUN SCRIPT', {scriptName, scriptWithArgs, args, env}); // console.log(require('node:util').inspect(parsed, {depth: 4, colors: true})); return run(parsed, env); } // let cacheStore; (async () => { // if (process.env.COMPILECACHE) installCache(); const script = process.argv[2]; if (!script) panic('No script name provided.'); const start = performance.now(); try { // eslint-disable-next-line require-atomic-updates process.exitCode = await runScript(script, process.argv.slice(3)); } finally { let worker; while ((worker = workerPool.workers?.pop())) worker.terminate(); if (DEBUG.timing) { console.log(bold(dim(`Done in ${(performance.now() - start) | 0}ms:`))); const dur = (ms) => (ms < 1 ? `${(ms * 1000) | 0}µs` : `${ms | 0}ms`); for (const entry of performance.getEntriesByType('measure')) { const pfx = entry.detail.depth ? ' '.repeat(entry.detail.depth) : ''; console.log(dim(`${pfx}⏱ ${dur(entry.duration)}: ${entry.name}`)); } } } })(); /* function installCache() { console.log('install cache'); const Module = require('node:module'); const crypto = require('node:crypto'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); class FileSystemBlobStore { constructor(directory) { this._blobFilename = path.join(directory, 'BLOB'); this._mapFilename = path.join(directory, 'MAP'); try { this._storedBlob = fs.readFileSync(this._blobFilename); this._storedMap = new Map( Object.entries(JSON.parse(fs.readFileSync(this._mapFilename))), ); } catch (e) { this._storedBlob = Buffer.alloc(0); this._storedMap = new Map(); } this._dirty = false; this._memoryBlobs = new Map(); this._invalidationKeys = new Map(); } has(key, invalidationKey) { if (this._memoryBlobs.has(key)) { return this._invalidationKeys.get(key) === invalidationKey; } else if (this._storedMap.has(key)) { return this._storedMap.get(key)[0] === invalidationKey; } return false; } get(key, invalidationKey) { if (this._memoryBlobs.has(key)) { if (this._invalidationKeys.get(key) === invalidationKey) { return this._memoryBlobs.get(key); } } else if (this._storedMap.has(key)) { const mapping = this._storedMap.get(key); if (mapping[0] === invalidationKey) { return this._storedBlob.slice(mapping[1], mapping[2]); } } } set(key, invalidationKey, buffer) { this._invalidationKeys.set(key, invalidationKey); this._memoryBlobs.set(key, buffer); this._dirty = true; } delete(key) { const d1 = this._memoryBlobs.delete(key); const d2 = this._invalidationKeys.delete(key); const d3 = this._storedMap.delete(key); if (d1 || d2 || d3) this._dirty = true; } save() { if (!this._dirty) return; const dir = path.dirname(this._blobFilename); const lock = path.join(dir, 'LOCK'); try { fs.mkdirSync(dir, {recursive: true}); } catch (_) {} try { fs.writeFileSync(lock, 'LOCK', {flag: 'wx'}); } catch (_) { return; } const dump = this._getDump(); try { fs.writeFileSync(this._blobFilename, Buffer.concat(dump[0])); fs.writeFileSync(this._mapFilename, JSON.stringify(dump[1])); } finally { fs.unlinkSync(lock); } } _getDump() { const buffers = []; const newMap = {}; let offset = 0; function push(key, invalidationKey, buffer) { buffers.push(buffer); newMap[key] = [invalidationKey, offset, offset + buffer.length]; offset += buffer.length; } for (const [key, buffer] of this._memoryBlobs.entries()) { const invalidationKey = this._invalidationKeys.get(key); push(key, invalidationKey, buffer); } for (const [key, mapping] of this._storedMap.entries()) { const buffer = this._storedBlob.slice(mapping[1], mapping[2]); push(key, mapping[0], buffer); } return [buffers, newMap]; } } cacheStore = new FileSystemBlobStore( path.join( process.cwd(), 'node_modules/.runv8cache', process.arch + process.versions.v8, ), ); // function compileModule(filename, content) { // const contLen = content.length; // if (contLen >= 2) { // if (content.charCodeAt(0) === 35 && content.charCodeAt(1) === 33) { // if (contLen === 2) { // // Exact match // content = ''; // } else { // // Find end of shebang line and slice it off // let i = 2; // for (; i < contLen; ++i) { // const code = content.charCodeAt(i); // if (code === 10 || code === 13) break; // } // if (i === contLen) { // content = ''; // } else { // // Note that this actually includes the newline character(s) in the // // new output. This duplicates the behavior of the regular // // expression that was previously used to replace the shebang line // content = content.slice(i); // } // } // } // } // const invalidationKey = crypto // .createHash('sha1') // .update(content, 'utf8') // .digest('hex'); // const script = new vm.Script(Module.wrap(content), { // filename, // lineOffset: 0, // displayErrors: true, // cachedData: cacheStore.get(filename, invalidationKey), // produceCachedData: true, // }); // if (script.cachedDataProduced) { // cacheStore.set(filename, invalidationKey, script.cachedData); // } else if (script.cachedDataRejected) { // cacheStore.delete(filename); // } // const compiledWrapper = script.runInThisContext({ // filename, // lineOffset: 0, // columnOffset: 0, // displayErrors: true, // }); // return compiledWrapper; // } // Module.prototype._compile = function (content, filename) { // const mod = this; // function require(id) { // return mod.require(id); // } // require.resolve = function (request, options) { // return Module._resolveFilename(request, mod, false, options); // }; // require.resolve.paths = (req) => Module._resolveLookupPaths(req, mod, true); // require.main = process.mainModule; // require.extensions = Module._extensions; // require.cache = Module._cache; // return compileModule(filename, content).call( // mod.exports, // mod.exports, // require, // mod, // filename, // path.dirname(filename), // process, // global, // ); // }; process.once('exit', () => cacheStore.save()); } */ This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,202 @@ { const Module = require('node:module'); const crypto = require('node:crypto'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); class FileSystemBlobStore { constructor(directory) { this._blobFilename = path.join(directory, 'BLOB'); this._mapFilename = path.join(directory, 'MAP'); try { this._storedBlob = fs.readFileSync(this._blobFilename); this._storedMap = new Map( Object.entries(JSON.parse(fs.readFileSync(this._mapFilename))), ); } catch (e) { this._storedBlob = Buffer.alloc(0); this._storedMap = new Map(); } this._dirty = false; this._memoryBlobs = new Map(); this._invalidationKeys = new Map(); } has(key, invalidationKey) { if (this._memoryBlobs.has(key)) { return this._invalidationKeys.get(key) === invalidationKey; } else if (this._storedMap.has(key)) { return this._storedMap.get(key)[0] === invalidationKey; } return false; } get(key, invalidationKey) { if (this._memoryBlobs.has(key)) { if (this._invalidationKeys.get(key) === invalidationKey) { return this._memoryBlobs.get(key); } } else if (this._storedMap.has(key)) { const mapping = this._storedMap.get(key); if (mapping[0] === invalidationKey) { return this._storedBlob.slice(mapping[1], mapping[2]); } } } set(key, invalidationKey, buffer) { this._invalidationKeys.set(key, invalidationKey); this._memoryBlobs.set(key, buffer); this._dirty = true; } delete(key) { const d1 = this._memoryBlobs.delete(key); const d2 = this._invalidationKeys.delete(key); const d3 = this._storedMap.delete(key); if (d1 || d2 || d3) this._dirty = true; } save() { if (!this._dirty) return; const dump = this._getDump(); const blobToStore = Buffer.concat(dump[0]); const mapToStore = JSON.stringify(dump[1]); const lock = path.join(path.dirname(this._blobFilename), 'LOCK'); try { fs.mkdirSync(lock, {recursive: true}); fs.writeFileSync(this._lockFilename, 'LOCK', {flag: 'wx'}); } catch (error) { // Swallow the exception if we fail to acquire the lock. return false; } try { fs.writeFileSync(this._blobFilename, blobToStore); fs.writeFileSync(this._mapFilename, mapToStore); } finally { fs.unlinkSync(lock); } return true; } _getDump() { const buffers = []; const newMap = {}; let offset = 0; function push(key, invalidationKey, buffer) { buffers.push(buffer); newMap[key] = [invalidationKey, offset, offset + buffer.length]; offset += buffer.length; } for (const [key, buffer] of this._memoryBlobs.entries()) { const invalidationKey = this._invalidationKeys[key]; push(key, invalidationKey, buffer); } for (const [key, mapping] of this._storedMap.entries()) { const buffer = this._storedBlob.slice(mapping[1], mapping[2]); push(key, mapping[0], buffer); } return [buffers, newMap]; } } const cacheStore = new FileSystemBlobStore( path.join( process.cwd(), 'node_modules/.runv8cache', process.arch + process.versions.v8, ), ); function compileModule(filename, content) { const contLen = content.length; if (contLen >= 2) { if ( content.charCodeAt(0) === 35 /* #*/ && content.charCodeAt(1) === 33 /* !*/ ) { if (contLen === 2) { // Exact match content = ''; } else { // Find end of shebang line and slice it off let i = 2; for (; i < contLen; ++i) { const code = content.charCodeAt(i); if (code === 10 /* \n*/ || code === 13 /* \r*/) break; } if (i === contLen) { content = ''; } else { // Note that this actually includes the newline character(s) in the // new output. This duplicates the behavior of the regular // expression that was previously used to replace the shebang line content = content.slice(i); } } } } const invalidationKey = crypto .createHash('sha1') .update(content, 'utf8') .digest('hex'); const script = new vm.Script(Module.wrap(content), { filename, lineOffset: 0, displayErrors: true, cachedData: cacheStore.get(filename, invalidationKey), produceCachedData: true, }); if (script.cachedDataProduced) { cacheStore.set(filename, invalidationKey, script.cachedData); } else if (script.cachedDataRejected) { cacheStore.delete(filename); } const compiledWrapper = script.runInThisContext({ filename, lineOffset: 0, columnOffset: 0, displayErrors: true, }); return compiledWrapper; } Module.prototype._compile = function (content, filename) { const mod = this; function require(id) { return mod.require(id); } require.resolve = function (request, options) { return Module._resolveFilename(request, mod, false, options); }; require.resolve.paths = (req) => Module._resolveLookupPaths(req, mod, true); require.main = process.mainModule; require.extensions = Module._extensions; require.cache = Module._cache; return compileModule(filename, content).call( mod.exports, mod.exports, require, mod, filename, path.dirname(filename), process, global, ); }; process.once('exit', () => cacheStore.save()); }