microsoft / node-api-dotnet

Advanced interoperability between .NET and JavaScript in the same process.
MIT License
521 stars 56 forks source link

How to make this work in powershell? #366

Open steve02081504 opened 2 months ago

steve02081504 commented 2 months ago

I tried to create a PowerShell module to run JS in PowerShell. Image

However, in reality, not only can I not call it normally after loading the module, but I also cannot use Node.js normally.

Before loading the module, Node.js runs well in my shell: Image Loading the module and trying to run a simple script results in an error: Image Subsequently, both the Node.js command and the JS code running function of the esh cannot be used normally: Image

jasongin commented 2 months ago

I've never tried using it in PowerShell before. I don't quite understand what's going wrong here, but I will try to investigate.

jasongin commented 2 months ago

I looked into this a little bit. Here is the inner exception message for the "exception thrown from JS thread":

There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: [Microsoft.JavaScri…t("console.log(1)")

I made a small PR that will make that inner exception message easier to see for situations like this: #378

Now the actual problem is that PowerShell expects to run scripts on a certain thread (with an associated "runspace") but JavaScript also must run on a particular thread. The Action delegate passed to the Run method gets invoked on the JS thread, but since that delegate is actually a PS script it cannot be executed on that thread.

Currently the NodejsEnvironment class always creates a dedicated thread for each JS environment, so that doesn't allow PS and JS scripts to run on the same thread. However @vmoroz is working on some changes to the libnode embedding API that will give us more flexibility to execute JS on a specific (existing) thread, which I think can work better for interaction with PowerShell.

Another workaround could be to add a NodejsEnvironment.RunScript() and/or RunScriptAsync() method which would run the given script on the JS thread without needing a callback.