graaljs
graaljs copied to clipboard
Does java embed runtime support typescript
When I try to import the openai library, I throw syntax error exceptions
npm install openai
Hi, can you share the stacktrace of the issue and how you import the library, for clarification
Hi, can you share the stacktrace of the issue and how you import the library, for clarification
I am sorry for the late reply.
graalVM version: 17.0.6
Here is the java code
package org.example;
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.io.FileSystem;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class HelloPolyglot {
public static void main(String[] args) throws IOException {
Map<String, String> options = new HashMap<>();
options.put("js.commonjs-require", "true");
String node_modules = Paths.get("node_modules").toAbsolutePath().toString();
options.put("js.commonjs-require-cwd", node_modules);
FileSystem fileSystem = FileSystem.newDefaultFileSystem();
fileSystem.setCurrentWorkingDirectory(Paths.get("node_modules").toAbsolutePath());
Context cx = Context.newBuilder("js")
.allowExperimentalOptions(true)
.allowIO(true)
.fileSystem(fileSystem)
.options(options)
.build();
String code = Files.readString(Paths.get("t.js"));
Value module = cx.eval("js", code);
}
}
node_modules is generated using npm install openai
package.json
{
"dependencies": {
"openai": "^3.2.1"
}
}
t.js is stored in js code, in a separate file for easy editing
const { Configuration, OpenAIApi } = require("openai/common.ts");
const configuration = new Configuration({
apiKey: ".....",
});
const openai = new OpenAIApi(configuration);
const response = await openai.createCompletion({
model: "text-davinci-003",
prompt: "Say this is a test",
temperature: 0,
max_tokens: 7,
});
print(response);
The running code throws the following exception message
Exception in thread "main" SyntaxError: Unnamed:6:23 Expected ; but found openai
const response = await openai.createCompletion({
^
Unnamed:8:10 Expected ; but found :
prompt: "Say this is a test",
^
Unnamed:10:14 Expected ; but found :
max_tokens: 7,
^
Unnamed:11:0 Expected eof but found }
});
^
at org.graalvm.sdk/org.graalvm.polyglot.Context.eval(Context.java:425)
at org.example.HelloPolyglot.main(HelloPolyglot.java:27)
Process finished with exit code 1
SyntaxError: Unnamed:6:23 Expected ; but found openai
const response = await openai.createCompletion({
^
This syntax error is caused by the fact that you attempt to use await outside async function. Just put the whole source into an async function:
(async () => {
// your original t.js
})();
Also note that JavaScript engines (including v8/Node.js and graaljs) do not support TypeScript directly typically. TypeScript sources are usually transpiled into JavaScript sources during installation of the corresponding package and the resulting JavaScript sources are used instead. In other words, do not require openai/common.ts, this will not work. Require openai/dist/index.js instead.
(async () => { // your original t.js })();
After your guidance, I changed the code to the following form, but it doesn't seem to work as expected HelloPolyglot.java
public class HelloPolyglot {
public static void main(String[] args) throws IOException, InterruptedException {
Map<String, String> options = new HashMap<>();
options.put("js.commonjs-require", "true");
String node_modules = Paths.get("node_modules").toAbsolutePath().toString();
options.put("js.commonjs-require-cwd", node_modules);
FileSystem fileSystem = FileSystem.newDefaultFileSystem();
fileSystem.setCurrentWorkingDirectory(Paths.get("node_modules").toAbsolutePath());
Context cx = Context.newBuilder("js")
.allowExperimentalOptions(true)
.allowIO(true)
.fileSystem(fileSystem)
.options(options)
.build();
String code = Files.readString(Paths.get("t.js"));
Value v = cx.eval("js", code);
System.out.println(v.toString());
Thread.currentThread().join();
}
}
t.js
const { Configuration, OpenAIApi } = require("openai/dist/index.js");
console.log("111")
const fun = (async () => {
console.log("async in ")
const configuration = new Configuration({
apiKey: ".....",
});
console.log("configuration")
const openai = new OpenAIApi(configuration);
console.log("openai")
const response = await openai.createCompletion({
model: "text-davinci-003",
prompt: "Say this is a test",
temperature: 0,
max_tokens: 7,
});
console.log("response")
console.log(response)
});
fun();
console.log("222")
Console output
111
async in
222
undefined
It seems that from the new Configuration onwards, the code does not execute properly, and the console does not see any error messages
and the console does not see any error messages
Errors from async functions are not printed by default. They reject the promise returned by the async function. You have various options to see the error:
- add
catchhandler to the returned promise (i.e.fun().catch(e => console.log(e));) - wrap the problematic code in the async function with
try-catchblock - set
js.unhandled-rejectionscontext option towarn
Note that the last alternative would print also unhandled promise rejections from other sources. This may be both helpful (when they are relevant) and confusing (when they are not relevant to you).
- .catch(e => console.log(e))
Thanks, I can now print out the error message using fun().catch(e => console.log(e));
From the information, it seems that the import failed. The console information is as follows:
111
async in
222
TypeError: Cannot load module: 'util'
undefined
Node that ECMAScript (=JavaScript) specification does not define any object that would allow you to interact with the outer world, i.e., it does not have support for filesystem access, network access, input/output etc.
JavaScript engines (like graaljs) typically implement the specification and add very little support for the interaction with the outer world - like functions for reading from the standard input and writing to the standard output. They do not provide advanced stuff like filesystem or network access, for example.
It is on the embedder of the JavaScript engine to provide the needed stuff. Web browsers do so through various Web APIs (like XMLHttpRequest, WebSocket API etc.) Node.js does so through their core modules (fs, http etc.)
util is a core Node.js module. graals (being "only" a JavaScript engine) does not provide any replacement for this (or any other core Node.js) module. It is up to you (= the embedder of JavaScript engine) to provide the needed stuff.
Sometimes, you can use the replacements provided by browserify or webpack frameworks but if your application needs some non-trivial interaction with the outer world (for example, performs an HTTP request) then these replacements will not work in a plain JavaScript engine (as the replacement has to depend on features provided by the target environment i.e. browsers in this case).
In summary, our CommonJS support will allow out-of-the-box execution of Node.js applications that do not need non-trivial interaction with the outer world only. For other applications, it is up to you to provide the needed functionality (through Java/JavaScript interoperability, for example).