View Source NodeJS

Build Status Hex.pm License: MIT Coverage Status

Provides an Elixir API for calling Node.js functions.

Documentation

The docs can be found at https://hexdocs.pm/nodejs.

Prerequisites

  • Elixir >= 1.7
  • NodeJS >= 10

Installation

def deps do
  [
    {:nodejs, "~> 3.2"}
  ]
end

Starting the service

Add NodeJS to your Supervisor as a child, pointing the required path option at the directory containing your JavaScript modules.

supervisor(NodeJS, [[path: "/node_app_root", pool_size: 4]])

Debug Mode

When working with Node.js applications, you may encounter debug messages or warnings from the Node.js runtime, especially when using inspector or debugging tools. To properly handle these messages:

# In your config/dev.exs or other appropriate config file
config :nodejs, debug_mode: true

When debug_mode is enabled:

  • Node.js stdout/stderr messages will be logged at the info level
  • Messages like "Debugger listening on..." will not cause errors
  • All Node.js processes will log their output through Elixir's Logger

This is particularly useful during development or when debugging Node.js integration issues.

Custom Node.js executable

By default the worker locates node on your PATH. To use a specific binary, for example in a release or container where node is not on the PATH, set:

config :nodejs, executable_path: "/usr/local/bin/node"

Calling JavaScript module functions with NodeJS.call(module, args \\ []).

If the module exports a function directly, like this:

module.exports = (x) => x

You can call it like this:

NodeJS.call("echo", ["hello"]) #=> {:ok, "hello"}

There is also a call! form that throws on error instead of returning a tuple:

NodeJS.call!("echo", ["hello"]) #=> "hello"

If the module exports an object with named functions like:

exports.add = (a, b) => a + b
exports.sub = (a, b) => a - b

You can call them like this:

NodeJS.call({"math", :add}, [1, 2]) # => {:ok, 3}
NodeJS.call({"math", :sub}, [1, 2]) # => {:ok, -1}

In order to cope with Unicode character it is necessary to specify the binary option:

NodeJS.call("echo", ["’"], binary: true) # => {:ok, "’"}

There Are Rules & Limitations (Unfortunately)

  • Function arguments must be serializable to JSON.
  • Return values must be serializable to JSON. (Objects with circular references will definitely fail.)
  • Modules must be requested relative to the path that was given to the Supervisor. E.g., for a path of /node_app_root and a file /node_app_root/foo/index.js your module request should be for "foo/index.js" or "foo/index" or "foo".

Running the tests

Since the test suite requires npm dependencies before you can run the tests you will first need to run

  cd test/js && npm install && cd ../..

After that you should be able to run

  mix test

Handling Callbacks and Promises

You can see examples of using promises in the tests here:

https://github.com/revelrylabs/elixir-nodejs/blob/master/test/nodejs_test.exs#L125

and from the JavaScript code here:

module.exports = async function echo(x, delay = 1000) {
  return new Promise((resolve) => setTimeout(() => resolve(x), delay))
}

https://github.com/revelrylabs/elixir-nodejs/blob/master/test/js/slow-async-echo.js