bytecodealliance / javy

JS to WebAssembly toolchain
Apache License 2.0
2.16k stars 103 forks source link

Uncaught Error: Dynamic require is not supported #568

Closed rahul007-bit closed 9 months ago

rahul007-bit commented 9 months ago

Hi,

I am working on a runtime where I am running the Hono application, and I have added all the required shims like URL, URLSearchParams, Headers, Request, Response, and path module.

This is how I am adding the shims to the runtime

let runtime = Runtime::default();
let context = runtime.context();

let source = fs::read_to_string("/src/index.js");
let mut contents = String::new();
let mut path = String::new();

contents.push_str(POLYFILL);
contents.push_str(&source.unwrap());
path.push_str(POLYFILL_PATH);

match context.eval_module("path", &path) {
    Ok(_) => {}
    Err(err) => eprintln!("Error loading the path shim: {err}"),
};

context.eval_module("handler.mjs", &contents).unwrap();

but the issue is that when I import this typeorm I get this error Uncaught Error: Dynamic require of "path" is not supported

is there any workaround for this issue?

Thanks!

jeffcharles commented 9 months ago

I need more context to understand the issue. The error message you've reported doesn't appear to be part of Javy or QuickJS's codebases.

When are you seeing the Uncaught Error: Dynamic require of "path" is not supported error message? When trying to compile the Wasm module? Is it at runtime?

Can you include a snippet of how you're importing the typeorm NPM package? Are you using a bundler like esbuild or vite?

rahul007-bit commented 9 months ago

The flow of my project is something like this,

first I have a SDK that complies to WASM binary and the above code is part of the SDK, and then the other part where I use actix_web with wasmtime so when there a request we invoke the wasm module and pass the request to it.

The error only occurs in runtime when we eval the handler.mjs module.

Here is the block of code where I am importing the typeorm

import { Hono } from 'hono'
import { createConnection, getManager } from "typeorm";
const app = new Hono();

app.get('/hello/:name', async (c) => {
    const name = c.req.param('name');
    return c.text(`Async Hello ${name}!`)
});

export default app;

For bundling the javascript project I am using esbuild

while debugging the build file I came across this block of code

var ce = ((n) =>
  typeof require < "u"
    ? require
    : typeof Proxy < "u"
    ? new Proxy(n, { get: (e, t) => (typeof require < "u" ? require : e)[t] })
    : n)(function (n) {
  if (typeof require < "u") return require.apply(this, arguments);
  throw Error('Dynamic require of "' + n + '" is not supported');
});

I think this part is checking whether the environment supports require or not.

jeffcharles commented 9 months ago

It looks to me like that snippet of code is introduced by esbuild from https://github.com/evanw/esbuild/blob/8d6d3ebf93b5987ad7457cb5cdc9e8d47afc68f7/internal/runtime/runtime.go#L131. The issue is something in typeorm or imported by typeorm is trying to pass a value to require instead of using a constant value so esbuild can't resolve the require ahead of time and instead inserts code to try to resolve it at runtime using require. Javy doesn't support require so there's a crash at runtime. The reason Javy doesn't support require is that QuickJS doesn't support require and Javy uses QuickJS as its JS interpreter.

You could try writing an implementation of a require function. Or maybe writing a plugin for esbuild to stub dynamic require calls. Otherwise, I'm not sure how to work around that limitation.

rahul007-bit commented 9 months ago

Thank you so much for your reply...

A last question from my side, while trying to add the require function I came across this esbuild banner feature and I added this into the build file

import { build } from 'esbuild'

build({
  entryPoints: ['src/index.js'],
  bundle: true,
  minify: true,
  outfile: 'bin/[...app].js',
  format: "esm",
  target: "esnext",
  platform: "node",
  banner: {
  js: [
    `import { createRequire as topLevelCreateRequire } from 'module';`,
    `const require = topLevelCreateRequire(import.meta.url);`,
  ].join(""),
},
}).catch((error) => {
  console.error(error)
  process.exit(1)
})

but I think quickjs does not support this module module, or am I doing something wrong?

or I have to add the require to globalThis.require = .....

jeffcharles commented 9 months ago

but I think quickjs does not support this module module,

Yeah that's a Node API. QuickJS doesn't provide Node APIs.

or I have to add the require to globalThis.require = .....

That may work. I haven't tried it before.

rahul007-bit commented 9 months ago

Then I have to try it...

But once again Thank you so much 🙏

I Think we can close this issue ✌️