microsoft / node-api-dotnet

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

Could not dynamically require Microsoft.JavaScript.NodeApi.node in Electron app #264

Closed 239573049 closed 3 months ago

239573049 commented 5 months ago

App threw an error during load Error: Could not dynamically require "D:\code\ai-dotnet-bot\client\dist-electron/win-x64/Microsoft.JavaScript.NodeApi.node". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work. at commonjsRequire (D:\code\ai-dotnet-bot\client\dist-electron\main.js:8:9) at initialize$1 (D:\code\ai-dotnet-bot\client\dist-electron\main.js:26:22) at Object. (D:\code\ai-dotnet-bot\client\dist-electron\main.js:34:14) at Module._compile (node:internal/modules/cjs/loader:1256:14) at Module._extensions..js (node:internal/modules/cjs/loader:1311:10) at Module.load (node:internal/modules/cjs/loader:1098:32) at Module._load (node:internal/modules/cjs/loader:945:12) at c._load (node:electron/js2c/node_init:2:13672) at cjsLoader (node:internal/modules/esm/translators:288:17) at ModuleWrap. (node:internal/modules/esm/translators:234:7)

jasongin commented 5 months ago

Did you try configuring dynamicRequireTargets as the error message suggests?

I don't have much experience with Electron, but I understand this is needed to give the bundler a hint about how to locate that .node file since the path passed to require() is dynamically computed rather than a constant. The reason it is "dynamic" is because it has to locate the native binary (.node file) corresponding to the current OS and CPU architecture.

Here is the relevant code. I guess if that code were changed to a big series of if-else cases for all supported OS + arch combinations, then each require call could be constant. But that sounds ugly.

239573049 commented 5 months ago

const dotnet = require('node-api-dotnet')

dotnet.System.Console.WriteLine("test")

This code executes without a problem.

import '../runtime/Microsoft.SemanticKernel'

const dotnet = require('node-api-dotnet')

dotnet.System.Console.WriteLine("test")

It was a mistake to join SemanticKernel

App threw an error during load Error: Could not load file or assembly 'D:\token\ai-dotnet-bot\client\dist-electron\main.dll'. 绯荤粺鎵句笉鍒版寚瀹氱殑鏂囦欢銆? at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)

jasongin commented 5 months ago

import '../runtime/Microsoft.SemanticKernel'

Could not load file or assembly 'D:\token\ai-dotnet-bot\client\dist-electron\main.dll'.

What JS file is this importing? The code in the .js file requires the file to have the same name as the assembly .dll file to be loaded. Have you renamed Microsoft.SemanticKernel.js to main.js? If so you'll have to change the code inside it that uses __filename.

jasongin commented 5 months ago

The problem is related to the bundling/packaging process of Electron, where __filename gets defined as "main" because the script files are all bundled together.

To work around it, replace this line in Microsoft.SemanticKernel.js:

-const assemblyName = path.basename(__filename, (__filename.match(/\.[cm]?js$/) || [])[0]);
+const assemblyName = 'Microsoft.SemanticKernel';

We can consider changing the generator tool to output the constant assembly name there instead of using __filename.

jasongin commented 3 months ago

Fixed by #303