#!/usr/bin/env node // Forward to the automatically-generated WebAssembly loader from the Go compiler const crypto = require('crypto'); const path = require('path'); const zlib = require('zlib'); const fs = require('fs'); const os = require('os'); const wasm_exec = path.join(__dirname, '..', 'wasm_exec.js'); const esbuild_wasm = path.join(__dirname, '..', 'esbuild.wasm'); const code = fs.readFileSync(wasm_exec, 'utf8'); const wrapper = new Function('require', 'module', 'process', 'WebAssembly', code); function instantiate(bytes, importObject) { // Using this API causes "./esbuild --version" to run around 1 second faster // than using the "WebAssembly.instantiate()" API when run in node (v12.16.2) const module = new WebAssembly.Module(bytes); const instance = new WebAssembly.Instance(module, importObject); return Promise.resolve({ instance, module }); } // Node has an unfortunate bug where the node process is unnecessarily kept open while a // WebAssembly module is being optimized: https://github.com/nodejs/node/issues/36616. // This means cases where running "esbuild" should take a few milliseconds can end up // taking many seconds instead. To work around this bug, it is possible to force node to // exit by calling the operating system's exit function. That's what this code does. process.on('exit', code => { // If it's a non-zero exit code, we can just kill our own process to stop. This will // preserve the fact that there is a non-zero exit code although the exit code will // be different. We cannot use this if the exit code is supposed to be zero. if (code !== 0) { try { process.kill(process.pid, 'SIGINT'); } catch (e) { } return; } // Otherwise if the exit code is zero, try to fall back to a binary N-API module that // calls the operating system's "exit(0)" function. const nativeModule = `${process.platform}-${os.arch()}-${os.endianness()}.node`; const base64 = require('../exit0')[nativeModule]; if (base64) { try { const data = zlib.inflateRawSync(Buffer.from(base64, 'base64')); const hash = crypto.createHash('sha256').update(base64).digest().toString('hex').slice(0, 16); const tempFile = path.join(os.tmpdir(), `${hash}-${nativeModule}`); try { if (fs.readFileSync(tempFile).equals(data)) { require(tempFile); } } finally { fs.writeFileSync(tempFile, data); require(tempFile); } } catch (e) { } } }); // Node has another bug where using "fs.read" to read from stdin reads // everything successfully and then throws an error, but only on Windows. Go's // WebAssembly support uses "fs.read" so it hits this problem. This is a patch // to try to work around the bug in node. This bug has been reported to node // at least twice in https://github.com/nodejs/node/issues/35997 and in // https://github.com/nodejs/node/issues/19831. This issue has also been // reported to the Go project: https://github.com/golang/go/issues/43913. const read = fs.read; fs.read = function () { const callback = arguments[5]; arguments[5] = function (err, count) { if (count === 0 && err && err.code === 'EOF') { arguments[0] = null; } return callback.apply(this, arguments); }; return read.apply(this, arguments); }; const argv = ['node', wasm_exec, esbuild_wasm].concat(process.argv.slice(2)); wrapper(require, require.main, Object.assign(Object.create(process), { argv }), Object.assign(Object.create(WebAssembly), { instantiate }));