Getting started

edit

Install the package and Node.js

Add the Meziantou.Framework.NodeJs package to a project:

dotnet package add Meziantou.Framework.NodeJs

The package does not include Node.js. Install Node.js 16.9 or later on the machines that run your application, and check that the node executable is in the PATH:

node --version

When node is not in the PATH, set NodeJsHostOptions.NodeExecutablePath, as described in Configuring the Node.js process.

The examples of this documentation omit the using directives: they need using Meziantou.Framework.NodeJs;, and using System.Text.Json; or using System.Text.Json.Nodes; for the JSON types.

Run JavaScript code

Start a Node.js process, evaluate code, and call a function of a built-in module:

await using var node = await NodeJsHost.StartAsync();

// Evaluate code as the body of an async function
var sum = await node.EvaluateAsync("return 1 + 2;");
Assert.Equal(3, sum.GetInt32());

// Call a function exported by a module: a file, a package, or a built-in module
var text = await node.InvokeAsync("node:util", "format", ["%s has %d items", "cart", 3]);
Assert.Equal("cart has 3 items", text.GetString());
  • NodeJsHost.StartAsync starts the node process. The host is disposable: the await using declaration stops the process.
  • EvaluateAsync runs the code as the body of an async function and returns the JSON representation of its result, as a JsonElement.
  • InvokeAsync imports a module and calls one of its exports with the arguments. node:util is a built-in module of Node.js; the next example calls a file of your own.

Call your own JavaScript

Put your JavaScript code in a module, such as scripts/slug.mjs:

// Turns a title into a URL segment: "Hello, World!" becomes "hello-world"
export function slugify(title) {
  return title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
}

// An export that is not a function
export const separator = '-';

Copy the folder to the output directory of your application, for instance with <None Update="scripts/**" CopyToOutputDirectory="PreserveNewest" /> in the project file. Then use it as the working directory of the process, and call the function:

await using var node = await NodeJsHost.StartAsync(new NodeJsHostOptions
{
    // The folder of the JavaScript files, copied to the output directory of the application
    WorkingDirectory = Path.Combine(AppContext.BaseDirectory, "scripts"),
});

var slug = await node.InvokeAsync<string>("./slug.mjs", "slugify", ["Hello, World!"]);
Assert.Equal("hello-world", slug);
  • A relative module path starts with ./ and includes the file extension. It is resolved from the working directory.
  • InvokeAsync<string> deserializes the result to a .NET type. See Arguments and results for the types you can use, and for the overloads that work with trimming and Native AOT.
  • Start one host and reuse it for many calls: starting a process is slow, and a module is loaded once per process. NodeJsHost is thread-safe.

Next steps