::: warning
This project depends on a PR to Node.js that adds
simpler ABI-stable embedding APIs to libnode. Until that PR is merged and the Node.js project
starts building shared libnode, we offer the
[Microsoft.JavaScript.LibNode](https://www.nuget.org/packages/Microsoft.JavaScript.LibNode) NuGet package that installs pre-built libnode` for Windows, MacOSX, and Linux (Ubuntu). This package
depends on the runtime ID specific NuGet packages which can be used directly if needed.
Since the PR for the ABI-stable embedding API is still work in progress, the built libnode
will have breaking changes between versions. See the Directory.Packages.props file in the
root of the node-api-dotnet project for the matching version of the Microsoft.JavaScript.LibNode
package.
- Load
libnodeand initialize a Node.js "platform" and "runtime" instance:
// Find the path to the libnode binary for the current platform.
string baseDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
string libnodePath = Path.Combine(baseDir, "libnode.dll");
NodeEmbeddingPlatform nodejsPlatform = new(libnodePath, null);
NodeEmbeddingThreadRuntime nodejsRuntime = nodejsPlatform.CreateThreadRuntime(baseDir,
new NodeEmbeddingRuntimeSettings
{
MainScript =
"globalThis.require = require('module').createRequire(process.execPath);\n"
});There can only be one
NodeEmbeddingPlatform
instance per process, so typically it would be stored in a static variable. From the platform,
multiple
NodeEmbeddingRuntime
or
NodeEmbeddingThreadRuntime
instances may be created and disposed.
The directory provided to the
NodeEmbeddingThreadRuntime
instance is the base for package resolution. Any packages or modules imported in the next step must
be installed (in a node_modules directory) in that base directory or a parent directory.
- Invoke a simple script from C#:
await nodejsRuntime.RunAsync(() =>
{
JSValue.RunScript("console.log('Hello from JS!');");
});Be aware of JavaScript's single-threaded execution model. All JavaScript operations must be
performed from the JS environment thread, unless otherwise noted. Use any of the Run(),
RunAsync(), Post(), or PostAsync() methods on the JS NodeEmbeddingThreadRuntime instance
to switch to the JS thread. Also keep in mind any JavaScript values of type JSValue (or any of
the more specific JS value struct types) are not valid after switching off the JS thread.
A JSReference can hold on to a JS value for future use. See also
JS Threading and Async Continuations and
JS References.
- Import modules or module properties:
// Import * from the `fluid-framework` module. Items exported from the module will be
// available as properties on the returned JS object.
JSValue fluidPackage = nodejsRuntime.Import("fluid-framework");
// Import just the `SharedString` class from the `fluid-framework` module.
JSValue sharedStringClass = nodejsRuntime.Import("fluid-framework", "SharedString");As explained above, importing modules must be done on the JS thread.
int pid = Process.GetCurrentProcess().Id;
Uri inspectionUri = nodejsRuntime.StartInspector();
Debug.WriteLine($"Node.js ({pid}) inspector listening at {inspectionUri}");Then attach a JavaScript debugger such as VS Code or Chrome to the inspection URI.