evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
38.19k stars 1.15k forks source link

TypeError [ERR_INVALID_URL]: Invalid URL - when running a bundle that includes tiny-secp256k1 #3039

Closed meglio closed 1 year ago

meglio commented 1 year ago

I'm building for node environment and using tiny-secp256k1 package.

The build is successful, but when running, an error is thrown:

node:internal/url:565
  throw new ERR_INVALID_URL(input);
  ^

TypeError [ERR_INVALID_URL]: Invalid URL
    at new NodeError (node:internal/errors:393:5)
    at URL.onParseError (node:internal/url:565:9)
    at new URL (node:internal/url:645:5)
    at path (/Users/.../.../.../esbuildtest/bin/jstools.js:19452:15)
    at Object.<anonymous> (/Users/.../.../.../esbuildtest/bin/jstools.js:19467:42)
    at Module._compile (node:internal/modules/cjs/loader:1159:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Module._load (node:internal/modules/cjs/loader:878:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
  input: 'secp256k1.wasm',
  code: 'ERR_INVALID_URL'
}

Here is that piece in the file with line 19452:

// node_modules/tiny-secp256k1/lib/wasm_path.js
var import_url = require("url");
var import_meta = {};
function path(wasmFilename) {
  const url = new import_url.URL(wasmFilename, import_meta.url);  // <- line 19452
  return (0, import_url.fileURLToPath)(url);
}

Am I doing it wrong, or is it a bug?

hyrious commented 1 year ago

This is because import.meta.url is not supported in your context (CJS or IIFE), it is only supported in ESM. So esbuild transforms that to var import_meta = {}.

Since your runtime is Node.js, you can do either:

meglio commented 1 year ago

So, if I go with the esm format, will it literally bundle the source wasm file into the bundle and make it automagically work?

meglio commented 1 year ago

I tried --format=esm. Building successful, but error when running:

file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:13
  throw new Error('Dynamic require of "' + x + '" is not supported');
        ^

Error: Dynamic require of "buffer" is not supported
    at file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:13:9
    at node_modules/bitcoinjs-lib/src/types.js (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:6419:20)
    at __require2 (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:16:51)
    at node_modules/bitcoinjs-lib/src/script_signature.js (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:6531:17)
    at __require2 (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:16:51)
    at node_modules/bitcoinjs-lib/src/script.js (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:6602:27)
    at __require2 (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:16:51)
    at node_modules/bitcoinjs-lib/src/payments/embed.js (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:6809:19)
    at __require2 (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:16:51)
    at node_modules/bitcoinjs-lib/src/payments/index.js (file:///Users/.../.../.../esbuildtest/bin/jstools.mjs:12372:19)

Node.js v18.12.1
hyrious commented 1 year ago

Dynamic require of "buffer" is not supported

That's another issue, that cjs code will be wrapped in a callback in esm bundle result in esbuild, and Node.js forbids any dynamic require on builtin modules. More details see #1921.

The best solution to this (not workarounds) IMO is to ensure all dependencies of your bundle are in ESM format. You can enable metafile and use the official analyzer to check it.

will it literally bundle the source wasm file into the bundle and make it automagically work?

To bundle a wasm file, first of all it has to be imported into the code with direct imports (import wasmBinary from './file.wasm'). Then you could make use of the wasm plugin to do so.

meglio commented 1 year ago

Okay, since I don't control how the packages use .wasm files, nor whether they are available in the ESM format, turns out this option is not viable.

Next, I should try --external:tiny-secp256k1. If I make it external, does it mean I'll have to npm i tiny-secp256k1 in the project's directory before I can call the bundled file? Or is there a better way? I'm trying to avoid installing packages with using npm, being my ultimate goal for using esbuild.

hyrious commented 1 year ago

Since your main purpose is creating a bundle.js with everything bundled in, it is not that hard to go with the wasm plugin approach. Let me give you a tiny example: https://gist.github.com/hyrious/311a8d7af354e94ab64a70a4da757e49

evanw commented 1 year ago

I'm closing this issue because this is not a problem with esbuild.