11cb0ef41Sopenharmony_ci# C++ embedder API 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci<!--introduced_in=v12.19.0--> 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciNode.js provides a number of C++ APIs that can be used to execute JavaScript 61cb0ef41Sopenharmony_ciin a Node.js environment from other C++ software. 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciThe documentation for these APIs can be found in [src/node.h][] in the Node.js 91cb0ef41Sopenharmony_cisource tree. In addition to the APIs exposed by Node.js, some required concepts 101cb0ef41Sopenharmony_ciare provided by the V8 embedder API. 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ciBecause using Node.js as an embedded library is different from writing code 131cb0ef41Sopenharmony_cithat is executed by Node.js, breaking changes do not follow typical Node.js 141cb0ef41Sopenharmony_ci[deprecation policy][] and may occur on each semver-major release without prior 151cb0ef41Sopenharmony_ciwarning. 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci## Example embedding application 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciThe following sections will provide an overview over how to use these APIs 201cb0ef41Sopenharmony_cito create an application from scratch that will perform the equivalent of 211cb0ef41Sopenharmony_ci`node -e <code>`, i.e. that will take a piece of JavaScript and run it in 221cb0ef41Sopenharmony_cia Node.js-specific environment. 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciThe full code can be found [in the Node.js source tree][embedtest.cc]. 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci### Setting up per-process state 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ciNode.js requires some per-process state management in order to run: 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci* Arguments parsing for Node.js [CLI options][], 311cb0ef41Sopenharmony_ci* V8 per-process requirements, such as a `v8::Platform` instance. 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciThe following example shows how these can be set up. Some class names are from 341cb0ef41Sopenharmony_cithe `node` and `v8` C++ namespaces, respectively. 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci```cpp 371cb0ef41Sopenharmony_ciint main(int argc, char** argv) { 381cb0ef41Sopenharmony_ci argv = uv_setup_args(argc, argv); 391cb0ef41Sopenharmony_ci std::vector<std::string> args(argv, argv + argc); 401cb0ef41Sopenharmony_ci // Parse Node.js CLI options, and print any errors that have occurred while 411cb0ef41Sopenharmony_ci // trying to parse them. 421cb0ef41Sopenharmony_ci std::unique_ptr<node::InitializationResult> result = 431cb0ef41Sopenharmony_ci node::InitializeOncePerProcess(args, { 441cb0ef41Sopenharmony_ci node::ProcessInitializationFlags::kNoInitializeV8, 451cb0ef41Sopenharmony_ci node::ProcessInitializationFlags::kNoInitializeNodeV8Platform 461cb0ef41Sopenharmony_ci }); 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci for (const std::string& error : result->errors()) 491cb0ef41Sopenharmony_ci fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str()); 501cb0ef41Sopenharmony_ci if (result->early_return() != 0) { 511cb0ef41Sopenharmony_ci return result->exit_code(); 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci // Create a v8::Platform instance. `MultiIsolatePlatform::Create()` is a way 551cb0ef41Sopenharmony_ci // to create a v8::Platform instance that Node.js can use when creating 561cb0ef41Sopenharmony_ci // Worker threads. When no `MultiIsolatePlatform` instance is present, 571cb0ef41Sopenharmony_ci // Worker threads are disabled. 581cb0ef41Sopenharmony_ci std::unique_ptr<MultiIsolatePlatform> platform = 591cb0ef41Sopenharmony_ci MultiIsolatePlatform::Create(4); 601cb0ef41Sopenharmony_ci V8::InitializePlatform(platform.get()); 611cb0ef41Sopenharmony_ci V8::Initialize(); 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci // See below for the contents of this function. 641cb0ef41Sopenharmony_ci int ret = RunNodeInstance( 651cb0ef41Sopenharmony_ci platform.get(), result->args(), result->exec_args()); 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci V8::Dispose(); 681cb0ef41Sopenharmony_ci V8::DisposePlatform(); 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci node::TearDownOncePerProcess(); 711cb0ef41Sopenharmony_ci return ret; 721cb0ef41Sopenharmony_ci} 731cb0ef41Sopenharmony_ci``` 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci### Per-instance state 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci<!-- YAML 781cb0ef41Sopenharmony_cichanges: 791cb0ef41Sopenharmony_ci - version: v15.0.0 801cb0ef41Sopenharmony_ci pr-url: https://github.com/nodejs/node/pull/35597 811cb0ef41Sopenharmony_ci description: 821cb0ef41Sopenharmony_ci The `CommonEnvironmentSetup` and `SpinEventLoop` utilities were added. 831cb0ef41Sopenharmony_ci--> 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ciNode.js has a concept of a “Node.js instance”, that is commonly being referred 861cb0ef41Sopenharmony_cito as `node::Environment`. Each `node::Environment` is associated with: 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci* Exactly one `v8::Isolate`, i.e. one JS Engine instance, 891cb0ef41Sopenharmony_ci* Exactly one `uv_loop_t`, i.e. one event loop, and 901cb0ef41Sopenharmony_ci* A number of `v8::Context`s, but exactly one main `v8::Context`. 911cb0ef41Sopenharmony_ci* One `node::IsolateData` instance that contains information that could be 921cb0ef41Sopenharmony_ci shared by multiple `node::Environment`s that use the same `v8::Isolate`. 931cb0ef41Sopenharmony_ci Currently, no testing if performed for this scenario. 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ciIn order to set up a `v8::Isolate`, an `v8::ArrayBuffer::Allocator` needs 961cb0ef41Sopenharmony_cito be provided. One possible choice is the default Node.js allocator, which 971cb0ef41Sopenharmony_cican be created through `node::ArrayBufferAllocator::Create()`. Using the Node.js 981cb0ef41Sopenharmony_ciallocator allows minor performance optimizations when addons use the Node.js 991cb0ef41Sopenharmony_ciC++ `Buffer` API, and is required in order to track `ArrayBuffer` memory in 1001cb0ef41Sopenharmony_ci[`process.memoryUsage()`][]. 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ciAdditionally, each `v8::Isolate` that is used for a Node.js instance needs to 1031cb0ef41Sopenharmony_cibe registered and unregistered with the `MultiIsolatePlatform` instance, if one 1041cb0ef41Sopenharmony_ciis being used, in order for the platform to know which event loop to use 1051cb0ef41Sopenharmony_cifor tasks scheduled by the `v8::Isolate`. 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ciThe `node::NewIsolate()` helper function creates a `v8::Isolate`, 1081cb0ef41Sopenharmony_cisets it up with some Node.js-specific hooks (e.g. the Node.js error handler), 1091cb0ef41Sopenharmony_ciand registers it with the platform automatically. 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci```cpp 1121cb0ef41Sopenharmony_ciint RunNodeInstance(MultiIsolatePlatform* platform, 1131cb0ef41Sopenharmony_ci const std::vector<std::string>& args, 1141cb0ef41Sopenharmony_ci const std::vector<std::string>& exec_args) { 1151cb0ef41Sopenharmony_ci int exit_code = 0; 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci // Setup up a libuv event loop, v8::Isolate, and Node.js Environment. 1181cb0ef41Sopenharmony_ci std::vector<std::string> errors; 1191cb0ef41Sopenharmony_ci std::unique_ptr<CommonEnvironmentSetup> setup = 1201cb0ef41Sopenharmony_ci CommonEnvironmentSetup::Create(platform, &errors, args, exec_args); 1211cb0ef41Sopenharmony_ci if (!setup) { 1221cb0ef41Sopenharmony_ci for (const std::string& err : errors) 1231cb0ef41Sopenharmony_ci fprintf(stderr, "%s: %s\n", args[0].c_str(), err.c_str()); 1241cb0ef41Sopenharmony_ci return 1; 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci Isolate* isolate = setup->isolate(); 1281cb0ef41Sopenharmony_ci Environment* env = setup->env(); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci { 1311cb0ef41Sopenharmony_ci Locker locker(isolate); 1321cb0ef41Sopenharmony_ci Isolate::Scope isolate_scope(isolate); 1331cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate); 1341cb0ef41Sopenharmony_ci // The v8::Context needs to be entered when node::CreateEnvironment() and 1351cb0ef41Sopenharmony_ci // node::LoadEnvironment() are being called. 1361cb0ef41Sopenharmony_ci Context::Scope context_scope(setup->context()); 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci // Set up the Node.js instance for execution, and run code inside of it. 1391cb0ef41Sopenharmony_ci // There is also a variant that takes a callback and provides it with 1401cb0ef41Sopenharmony_ci // the `require` and `process` objects, so that it can manually compile 1411cb0ef41Sopenharmony_ci // and run scripts as needed. 1421cb0ef41Sopenharmony_ci // The `require` function inside this script does *not* access the file 1431cb0ef41Sopenharmony_ci // system, and can only load built-in Node.js modules. 1441cb0ef41Sopenharmony_ci // `module.createRequire()` is being used to create one that is able to 1451cb0ef41Sopenharmony_ci // load files from the disk, and uses the standard CommonJS file loader 1461cb0ef41Sopenharmony_ci // instead of the internal-only `require` function. 1471cb0ef41Sopenharmony_ci MaybeLocal<Value> loadenv_ret = node::LoadEnvironment( 1481cb0ef41Sopenharmony_ci env, 1491cb0ef41Sopenharmony_ci "const publicRequire =" 1501cb0ef41Sopenharmony_ci " require('node:module').createRequire(process.cwd() + '/');" 1511cb0ef41Sopenharmony_ci "globalThis.require = publicRequire;" 1521cb0ef41Sopenharmony_ci "require('node:vm').runInThisContext(process.argv[1]);"); 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci if (loadenv_ret.IsEmpty()) // There has been a JS exception. 1551cb0ef41Sopenharmony_ci return 1; 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci exit_code = node::SpinEventLoop(env).FromMaybe(1); 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci // node::Stop() can be used to explicitly stop the event loop and keep 1601cb0ef41Sopenharmony_ci // further JavaScript from running. It can be called from any thread, 1611cb0ef41Sopenharmony_ci // and will act like worker.terminate() if called from another thread. 1621cb0ef41Sopenharmony_ci node::Stop(env); 1631cb0ef41Sopenharmony_ci } 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci return exit_code; 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci``` 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci[CLI options]: cli.md 1701cb0ef41Sopenharmony_ci[`process.memoryUsage()`]: process.md#processmemoryusage 1711cb0ef41Sopenharmony_ci[deprecation policy]: deprecations.md 1721cb0ef41Sopenharmony_ci[embedtest.cc]: https://github.com/nodejs/node/blob/HEAD/test/embedding/embedtest.cc 1731cb0ef41Sopenharmony_ci[src/node.h]: https://github.com/nodejs/node/blob/HEAD/src/node.h 174