{ "type": "module", "source": "doc/api/embedding.md", "modules": [ { "textRaw": "C++ embedder API", "name": "c++_embedder_api", "introduced_in": "v12.19.0", "desc": "<p>Node.js provides a number of C++ APIs that can be used to execute JavaScript\nin a Node.js environment from other C++ software.</p>\n<p>The documentation for these APIs can be found in <a href=\"https://github.com/nodejs/node/blob/HEAD/src/node.h\">src/node.h</a> in the Node.js\nsource tree. In addition to the APIs exposed by Node.js, some required concepts\nare provided by the V8 embedder API.</p>\n<p>Because using Node.js as an embedded library is different from writing code\nthat is executed by Node.js, breaking changes do not follow typical Node.js\n<a href=\"deprecations.html\">deprecation policy</a> and may occur on each semver-major release without prior\nwarning.</p>\n<h2>Example embedding application</h2>\n<p>The following sections will provide an overview over how to use these APIs\nto create an application from scratch that will perform the equivalent of\n<code>node -e <code></code>, i.e. that will take a piece of JavaScript and run it in\na Node.js-specific environment.</p>\n<p>The full code can be found <a href=\"https://github.com/nodejs/node/blob/HEAD/test/embedding/embedtest.cc\">in the Node.js source tree</a>.</p>", "modules": [ { "textRaw": "Setting up per-process state", "name": "setting_up_per-process_state", "desc": "<p>Node.js requires some per-process state management in order to run:</p>\n<ul>\n<li>Arguments parsing for Node.js <a href=\"cli.html\">CLI options</a>,</li>\n<li>V8 per-process requirements, such as a <code>v8::Platform</code> instance.</li>\n</ul>\n<p>The following example shows how these can be set up. Some class names are from\nthe <code>node</code> and <code>v8</code> C++ namespaces, respectively.</p>\n<pre><code class=\"language-cpp\">int main(int argc, char** argv) {\n argv = uv_setup_args(argc, argv);\n std::vector<std::string> args(argv, argv + argc);\n // Parse Node.js CLI options, and print any errors that have occurred while\n // trying to parse them.\n std::unique_ptr<node::InitializationResult> result =\n node::InitializeOncePerProcess(args, {\n node::ProcessInitializationFlags::kNoInitializeV8,\n node::ProcessInitializationFlags::kNoInitializeNodeV8Platform\n });\n\n for (const std::string& error : result->errors())\n fprintf(stderr, \"%s: %s\\n\", args[0].c_str(), error.c_str());\n if (result->early_return() != 0) {\n return result->exit_code();\n }\n\n // Create a v8::Platform instance. `MultiIsolatePlatform::Create()` is a way\n // to create a v8::Platform instance that Node.js can use when creating\n // Worker threads. When no `MultiIsolatePlatform` instance is present,\n // Worker threads are disabled.\n std::unique_ptr<MultiIsolatePlatform> platform =\n MultiIsolatePlatform::Create(4);\n V8::InitializePlatform(platform.get());\n V8::Initialize();\n\n // See below for the contents of this function.\n int ret = RunNodeInstance(\n platform.get(), result->args(), result->exec_args());\n\n V8::Dispose();\n V8::DisposePlatform();\n\n node::TearDownOncePerProcess();\n return ret;\n}\n</code></pre>", "type": "module", "displayName": "Setting up per-process state" }, { "textRaw": "Per-instance state", "name": "per-instance_state", "meta": { "changes": [ { "version": "v15.0.0", "pr-url": "https://github.com/nodejs/node/pull/35597", "description": "The `CommonEnvironmentSetup` and `SpinEventLoop` utilities were added." } ] }, "desc": "<p>Node.js has a concept of a “Node.js instanceâ€, that is commonly being referred\nto as <code>node::Environment</code>. Each <code>node::Environment</code> is associated with:</p>\n<ul>\n<li>Exactly one <code>v8::Isolate</code>, i.e. one JS Engine instance,</li>\n<li>Exactly one <code>uv_loop_t</code>, i.e. one event loop, and</li>\n<li>A number of <code>v8::Context</code>s, but exactly one main <code>v8::Context</code>.</li>\n<li>One <code>node::IsolateData</code> instance that contains information that could be\nshared by multiple <code>node::Environment</code>s that use the same <code>v8::Isolate</code>.\nCurrently, no testing if performed for this scenario.</li>\n</ul>\n<p>In order to set up a <code>v8::Isolate</code>, an <code>v8::ArrayBuffer::Allocator</code> needs\nto be provided. One possible choice is the default Node.js allocator, which\ncan be created through <code>node::ArrayBufferAllocator::Create()</code>. Using the Node.js\nallocator allows minor performance optimizations when addons use the Node.js\nC++ <code>Buffer</code> API, and is required in order to track <code>ArrayBuffer</code> memory in\n<a href=\"process.html#processmemoryusage\"><code>process.memoryUsage()</code></a>.</p>\n<p>Additionally, each <code>v8::Isolate</code> that is used for a Node.js instance needs to\nbe registered and unregistered with the <code>MultiIsolatePlatform</code> instance, if one\nis being used, in order for the platform to know which event loop to use\nfor tasks scheduled by the <code>v8::Isolate</code>.</p>\n<p>The <code>node::NewIsolate()</code> helper function creates a <code>v8::Isolate</code>,\nsets it up with some Node.js-specific hooks (e.g. the Node.js error handler),\nand registers it with the platform automatically.</p>\n<pre><code class=\"language-cpp\">int RunNodeInstance(MultiIsolatePlatform* platform,\n const std::vector<std::string>& args,\n const std::vector<std::string>& exec_args) {\n int exit_code = 0;\n\n // Setup up a libuv event loop, v8::Isolate, and Node.js Environment.\n std::vector<std::string> errors;\n std::unique_ptr<CommonEnvironmentSetup> setup =\n CommonEnvironmentSetup::Create(platform, &errors, args, exec_args);\n if (!setup) {\n for (const std::string& err : errors)\n fprintf(stderr, \"%s: %s\\n\", args[0].c_str(), err.c_str());\n return 1;\n }\n\n Isolate* isolate = setup->isolate();\n Environment* env = setup->env();\n\n {\n Locker locker(isolate);\n Isolate::Scope isolate_scope(isolate);\n HandleScope handle_scope(isolate);\n // The v8::Context needs to be entered when node::CreateEnvironment() and\n // node::LoadEnvironment() are being called.\n Context::Scope context_scope(setup->context());\n\n // Set up the Node.js instance for execution, and run code inside of it.\n // There is also a variant that takes a callback and provides it with\n // the `require` and `process` objects, so that it can manually compile\n // and run scripts as needed.\n // The `require` function inside this script does *not* access the file\n // system, and can only load built-in Node.js modules.\n // `module.createRequire()` is being used to create one that is able to\n // load files from the disk, and uses the standard CommonJS file loader\n // instead of the internal-only `require` function.\n MaybeLocal<Value> loadenv_ret = node::LoadEnvironment(\n env,\n \"const publicRequire =\"\n \" require('node:module').createRequire(process.cwd() + '/');\"\n \"globalThis.require = publicRequire;\"\n \"require('node:vm').runInThisContext(process.argv[1]);\");\n\n if (loadenv_ret.IsEmpty()) // There has been a JS exception.\n return 1;\n\n exit_code = node::SpinEventLoop(env).FromMaybe(1);\n\n // node::Stop() can be used to explicitly stop the event loop and keep\n // further JavaScript from running. It can be called from any thread,\n // and will act like worker.terminate() if called from another thread.\n node::Stop(env);\n }\n\n return exit_code;\n}\n</code></pre>", "type": "module", "displayName": "Per-instance state" } ], "type": "module", "displayName": "C++ embedder API" } ] }