1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width"> 6 <meta name="nodejs.org:node-version" content="v18.20.1"> 7 <title>C++ addons | Node.js v18.20.1 Documentation</title> 8 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic&display=fallback"> 9 <link rel="stylesheet" href="assets/style.css"> 10 <link rel="stylesheet" href="assets/hljs.css"> 11 <link rel="canonical" href="https://nodejs.org/api/addons.html"> 12 <script async defer src="assets/api.js" type="text/javascript"></script> 13 14</head> 15<body class="alt apidoc" id="api-section-addons"> 16 <div id="content" class="clearfix"> 17 <div id="column2" class="interior"> 18 <div id="intro" class="interior"> 19 <a href="/" title="Go back to the home page"> 20 Node.js 21 </a> 22 </div> 23 <ul> 24<li><a href="documentation.html" class="nav-documentation">About this documentation</a></li> 25<li><a href="synopsis.html" class="nav-synopsis">Usage and example</a></li> 26</ul> 27<hr class="line"> 28<ul> 29<li><a href="assert.html" class="nav-assert">Assertion testing</a></li> 30<li><a href="async_context.html" class="nav-async_context">Asynchronous context tracking</a></li> 31<li><a href="async_hooks.html" class="nav-async_hooks">Async hooks</a></li> 32<li><a href="buffer.html" class="nav-buffer">Buffer</a></li> 33<li><a href="addons.html" class="nav-addons active">C++ addons</a></li> 34<li><a href="n-api.html" class="nav-n-api">C/C++ addons with Node-API</a></li> 35<li><a href="embedding.html" class="nav-embedding">C++ embedder API</a></li> 36<li><a href="child_process.html" class="nav-child_process">Child processes</a></li> 37<li><a href="cluster.html" class="nav-cluster">Cluster</a></li> 38<li><a href="cli.html" class="nav-cli">Command-line options</a></li> 39<li><a href="console.html" class="nav-console">Console</a></li> 40<li><a href="corepack.html" class="nav-corepack">Corepack</a></li> 41<li><a href="crypto.html" class="nav-crypto">Crypto</a></li> 42<li><a href="debugger.html" class="nav-debugger">Debugger</a></li> 43<li><a href="deprecations.html" class="nav-deprecations">Deprecated APIs</a></li> 44<li><a href="diagnostics_channel.html" class="nav-diagnostics_channel">Diagnostics Channel</a></li> 45<li><a href="dns.html" class="nav-dns">DNS</a></li> 46<li><a href="domain.html" class="nav-domain">Domain</a></li> 47<li><a href="errors.html" class="nav-errors">Errors</a></li> 48<li><a href="events.html" class="nav-events">Events</a></li> 49<li><a href="fs.html" class="nav-fs">File system</a></li> 50<li><a href="globals.html" class="nav-globals">Globals</a></li> 51<li><a href="http.html" class="nav-http">HTTP</a></li> 52<li><a href="http2.html" class="nav-http2">HTTP/2</a></li> 53<li><a href="https.html" class="nav-https">HTTPS</a></li> 54<li><a href="inspector.html" class="nav-inspector">Inspector</a></li> 55<li><a href="intl.html" class="nav-intl">Internationalization</a></li> 56<li><a href="modules.html" class="nav-modules">Modules: CommonJS modules</a></li> 57<li><a href="esm.html" class="nav-esm">Modules: ECMAScript modules</a></li> 58<li><a href="module.html" class="nav-module">Modules: <code>node:module</code> API</a></li> 59<li><a href="packages.html" class="nav-packages">Modules: Packages</a></li> 60<li><a href="net.html" class="nav-net">Net</a></li> 61<li><a href="os.html" class="nav-os">OS</a></li> 62<li><a href="path.html" class="nav-path">Path</a></li> 63<li><a href="perf_hooks.html" class="nav-perf_hooks">Performance hooks</a></li> 64<li><a href="permissions.html" class="nav-permissions">Permissions</a></li> 65<li><a href="process.html" class="nav-process">Process</a></li> 66<li><a href="punycode.html" class="nav-punycode">Punycode</a></li> 67<li><a href="querystring.html" class="nav-querystring">Query strings</a></li> 68<li><a href="readline.html" class="nav-readline">Readline</a></li> 69<li><a href="repl.html" class="nav-repl">REPL</a></li> 70<li><a href="report.html" class="nav-report">Report</a></li> 71<li><a href="single-executable-applications.html" class="nav-single-executable-applications">Single executable applications</a></li> 72<li><a href="stream.html" class="nav-stream">Stream</a></li> 73<li><a href="string_decoder.html" class="nav-string_decoder">String decoder</a></li> 74<li><a href="test.html" class="nav-test">Test runner</a></li> 75<li><a href="timers.html" class="nav-timers">Timers</a></li> 76<li><a href="tls.html" class="nav-tls">TLS/SSL</a></li> 77<li><a href="tracing.html" class="nav-tracing">Trace events</a></li> 78<li><a href="tty.html" class="nav-tty">TTY</a></li> 79<li><a href="dgram.html" class="nav-dgram">UDP/datagram</a></li> 80<li><a href="url.html" class="nav-url">URL</a></li> 81<li><a href="util.html" class="nav-util">Utilities</a></li> 82<li><a href="v8.html" class="nav-v8">V8</a></li> 83<li><a href="vm.html" class="nav-vm">VM</a></li> 84<li><a href="wasi.html" class="nav-wasi">WASI</a></li> 85<li><a href="webcrypto.html" class="nav-webcrypto">Web Crypto API</a></li> 86<li><a href="webstreams.html" class="nav-webstreams">Web Streams API</a></li> 87<li><a href="worker_threads.html" class="nav-worker_threads">Worker threads</a></li> 88<li><a href="zlib.html" class="nav-zlib">Zlib</a></li> 89</ul> 90<hr class="line"> 91<ul> 92<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">Code repository and issue tracker</a></li> 93</ul> 94 </div> 95 96 <div id="column1" data-id="addons" class="interior"> 97 <header class="header"> 98 <div class="header-container"> 99 <h1>Node.js v18.20.1 documentation</h1> 100 <button class="theme-toggle-btn" id="theme-toggle-btn" title="Toggle dark mode/light mode" aria-label="Toggle dark mode/light mode" hidden> 101 <svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" height="24" width="24"> 102 <path fill="none" d="M0 0h24v24H0z" /> 103 <path d="M11.1 12.08c-2.33-4.51-.5-8.48.53-10.07C6.27 2.2 1.98 6.59 1.98 12c0 .14.02.28.02.42.62-.27 1.29-.42 2-.42 1.66 0 3.18.83 4.1 2.15A4.01 4.01 0 0111 18c0 1.52-.87 2.83-2.12 3.51.98.32 2.03.5 3.11.5 3.5 0 6.58-1.8 8.37-4.52-2.36.23-6.98-.97-9.26-5.41z"/> 104 <path d="M7 16h-.18C6.4 14.84 5.3 14 4 14c-1.66 0-3 1.34-3 3s1.34 3 3 3h3c1.1 0 2-.9 2-2s-.9-2-2-2z"/> 105 </svg> 106 <svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" height="24" width="24"> 107 <path d="M0 0h24v24H0z" fill="none" /> 108 <path d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"/> 109 </svg> 110 </button> 111 </div> 112 <div id="gtoc"> 113 <ul> 114 <li class="pinned-header">Node.js v18.20.1</li> 115 116 <li class="picker-header"> 117 <a href="#"> 118 <span class="collapsed-arrow">►</span><span class="expanded-arrow">▼</span> 119 Table of contents 120 </a> 121 122 <div class="picker"><div class="toc"><ul> 123<li><a href="#c-addons">C++ addons</a> 124<ul> 125<li><a href="#hello-world">Hello world</a> 126<ul> 127<li><a href="#context-aware-addons">Context-aware addons</a> 128<ul> 129<li><a href="#worker-support">Worker support</a></li> 130</ul> 131</li> 132<li><a href="#building">Building</a></li> 133<li><a href="#linking-to-libraries-included-with-nodejs">Linking to libraries included with Node.js</a></li> 134<li><a href="#loading-addons-using-require">Loading addons using <code>require()</code></a></li> 135</ul> 136</li> 137<li><a href="#native-abstractions-for-nodejs">Native abstractions for Node.js</a></li> 138<li><span class="stability_2"><a href="#node-api">Node-API</a></span></li> 139<li><a href="#addon-examples">Addon examples</a> 140<ul> 141<li><a href="#function-arguments">Function arguments</a></li> 142<li><a href="#callbacks">Callbacks</a></li> 143<li><a href="#object-factory">Object factory</a></li> 144<li><a href="#function-factory">Function factory</a></li> 145<li><a href="#wrapping-c-objects">Wrapping C++ objects</a></li> 146<li><a href="#factory-of-wrapped-objects">Factory of wrapped objects</a></li> 147<li><a href="#passing-wrapped-objects-around">Passing wrapped objects around</a></li> 148</ul> 149</li> 150</ul> 151</li> 152</ul></div></div> 153 </li> 154 155 156 <li class="picker-header"> 157 <a href="#"> 158 <span class="collapsed-arrow">►</span><span class="expanded-arrow">▼</span> 159 Index 160 </a> 161 162 <div class="picker"><ul> 163<li><a href="documentation.html" class="nav-documentation">About this documentation</a></li> 164<li><a href="synopsis.html" class="nav-synopsis">Usage and example</a></li> 165 166 <li> 167 <a href="index.html">Index</a> 168 </li> 169 </ul> 170 171<hr class="line"> 172<ul> 173<li><a href="assert.html" class="nav-assert">Assertion testing</a></li> 174<li><a href="async_context.html" class="nav-async_context">Asynchronous context tracking</a></li> 175<li><a href="async_hooks.html" class="nav-async_hooks">Async hooks</a></li> 176<li><a href="buffer.html" class="nav-buffer">Buffer</a></li> 177<li><a href="addons.html" class="nav-addons active">C++ addons</a></li> 178<li><a href="n-api.html" class="nav-n-api">C/C++ addons with Node-API</a></li> 179<li><a href="embedding.html" class="nav-embedding">C++ embedder API</a></li> 180<li><a href="child_process.html" class="nav-child_process">Child processes</a></li> 181<li><a href="cluster.html" class="nav-cluster">Cluster</a></li> 182<li><a href="cli.html" class="nav-cli">Command-line options</a></li> 183<li><a href="console.html" class="nav-console">Console</a></li> 184<li><a href="corepack.html" class="nav-corepack">Corepack</a></li> 185<li><a href="crypto.html" class="nav-crypto">Crypto</a></li> 186<li><a href="debugger.html" class="nav-debugger">Debugger</a></li> 187<li><a href="deprecations.html" class="nav-deprecations">Deprecated APIs</a></li> 188<li><a href="diagnostics_channel.html" class="nav-diagnostics_channel">Diagnostics Channel</a></li> 189<li><a href="dns.html" class="nav-dns">DNS</a></li> 190<li><a href="domain.html" class="nav-domain">Domain</a></li> 191<li><a href="errors.html" class="nav-errors">Errors</a></li> 192<li><a href="events.html" class="nav-events">Events</a></li> 193<li><a href="fs.html" class="nav-fs">File system</a></li> 194<li><a href="globals.html" class="nav-globals">Globals</a></li> 195<li><a href="http.html" class="nav-http">HTTP</a></li> 196<li><a href="http2.html" class="nav-http2">HTTP/2</a></li> 197<li><a href="https.html" class="nav-https">HTTPS</a></li> 198<li><a href="inspector.html" class="nav-inspector">Inspector</a></li> 199<li><a href="intl.html" class="nav-intl">Internationalization</a></li> 200<li><a href="modules.html" class="nav-modules">Modules: CommonJS modules</a></li> 201<li><a href="esm.html" class="nav-esm">Modules: ECMAScript modules</a></li> 202<li><a href="module.html" class="nav-module">Modules: <code>node:module</code> API</a></li> 203<li><a href="packages.html" class="nav-packages">Modules: Packages</a></li> 204<li><a href="net.html" class="nav-net">Net</a></li> 205<li><a href="os.html" class="nav-os">OS</a></li> 206<li><a href="path.html" class="nav-path">Path</a></li> 207<li><a href="perf_hooks.html" class="nav-perf_hooks">Performance hooks</a></li> 208<li><a href="permissions.html" class="nav-permissions">Permissions</a></li> 209<li><a href="process.html" class="nav-process">Process</a></li> 210<li><a href="punycode.html" class="nav-punycode">Punycode</a></li> 211<li><a href="querystring.html" class="nav-querystring">Query strings</a></li> 212<li><a href="readline.html" class="nav-readline">Readline</a></li> 213<li><a href="repl.html" class="nav-repl">REPL</a></li> 214<li><a href="report.html" class="nav-report">Report</a></li> 215<li><a href="single-executable-applications.html" class="nav-single-executable-applications">Single executable applications</a></li> 216<li><a href="stream.html" class="nav-stream">Stream</a></li> 217<li><a href="string_decoder.html" class="nav-string_decoder">String decoder</a></li> 218<li><a href="test.html" class="nav-test">Test runner</a></li> 219<li><a href="timers.html" class="nav-timers">Timers</a></li> 220<li><a href="tls.html" class="nav-tls">TLS/SSL</a></li> 221<li><a href="tracing.html" class="nav-tracing">Trace events</a></li> 222<li><a href="tty.html" class="nav-tty">TTY</a></li> 223<li><a href="dgram.html" class="nav-dgram">UDP/datagram</a></li> 224<li><a href="url.html" class="nav-url">URL</a></li> 225<li><a href="util.html" class="nav-util">Utilities</a></li> 226<li><a href="v8.html" class="nav-v8">V8</a></li> 227<li><a href="vm.html" class="nav-vm">VM</a></li> 228<li><a href="wasi.html" class="nav-wasi">WASI</a></li> 229<li><a href="webcrypto.html" class="nav-webcrypto">Web Crypto API</a></li> 230<li><a href="webstreams.html" class="nav-webstreams">Web Streams API</a></li> 231<li><a href="worker_threads.html" class="nav-worker_threads">Worker threads</a></li> 232<li><a href="zlib.html" class="nav-zlib">Zlib</a></li> 233</ul> 234<hr class="line"> 235<ul> 236<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">Code repository and issue tracker</a></li> 237</ul></div> 238 </li> 239 240 241 <li class="picker-header"> 242 <a href="#"> 243 <span class="collapsed-arrow">►</span><span class="expanded-arrow">▼</span> 244 Other versions 245 </a> 246 <div class="picker"><ol id="alt-docs"><li><a href="https://nodejs.org/docs/latest-v21.x/api/addons.html">21.x</a></li> 247<li><a href="https://nodejs.org/docs/latest-v20.x/api/addons.html">20.x <b>LTS</b></a></li> 248<li><a href="https://nodejs.org/docs/latest-v19.x/api/addons.html">19.x</a></li> 249<li><a href="https://nodejs.org/docs/latest-v18.x/api/addons.html">18.x <b>LTS</b></a></li> 250<li><a href="https://nodejs.org/docs/latest-v17.x/api/addons.html">17.x</a></li> 251<li><a href="https://nodejs.org/docs/latest-v16.x/api/addons.html">16.x</a></li> 252<li><a href="https://nodejs.org/docs/latest-v15.x/api/addons.html">15.x</a></li> 253<li><a href="https://nodejs.org/docs/latest-v14.x/api/addons.html">14.x</a></li> 254<li><a href="https://nodejs.org/docs/latest-v13.x/api/addons.html">13.x</a></li> 255<li><a href="https://nodejs.org/docs/latest-v12.x/api/addons.html">12.x</a></li> 256<li><a href="https://nodejs.org/docs/latest-v11.x/api/addons.html">11.x</a></li> 257<li><a href="https://nodejs.org/docs/latest-v10.x/api/addons.html">10.x</a></li> 258<li><a href="https://nodejs.org/docs/latest-v9.x/api/addons.html">9.x</a></li> 259<li><a href="https://nodejs.org/docs/latest-v8.x/api/addons.html">8.x</a></li> 260<li><a href="https://nodejs.org/docs/latest-v7.x/api/addons.html">7.x</a></li> 261<li><a href="https://nodejs.org/docs/latest-v6.x/api/addons.html">6.x</a></li> 262<li><a href="https://nodejs.org/docs/latest-v5.x/api/addons.html">5.x</a></li> 263<li><a href="https://nodejs.org/docs/latest-v4.x/api/addons.html">4.x</a></li> 264<li><a href="https://nodejs.org/docs/latest-v0.12.x/api/addons.html">0.12.x</a></li> 265<li><a href="https://nodejs.org/docs/latest-v0.10.x/api/addons.html">0.10.x</a></li></ol></div> 266 </li> 267 268 <li class="picker-header"> 269 <a href="#"> 270 <span class="collapsed-arrow">►</span><span class="expanded-arrow">▼</span> 271 Options 272 </a> 273 274 <div class="picker"> 275 <ul> 276 <li> 277 <a href="all.html">View on single page</a> 278 </li> 279 <li> 280 <a href="addons.json">View as JSON</a> 281 </li> 282 <li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/main/doc/api/addons.md">Edit on GitHub</a></li> 283 </ul> 284 </div> 285 </li> 286 </ul> 287 </div> 288 <hr> 289 </header> 290 291 <details id="toc" open><summary>Table of contents</summary><ul> 292<li><a href="#c-addons">C++ addons</a> 293<ul> 294<li><a href="#hello-world">Hello world</a> 295<ul> 296<li><a href="#context-aware-addons">Context-aware addons</a> 297<ul> 298<li><a href="#worker-support">Worker support</a></li> 299</ul> 300</li> 301<li><a href="#building">Building</a></li> 302<li><a href="#linking-to-libraries-included-with-nodejs">Linking to libraries included with Node.js</a></li> 303<li><a href="#loading-addons-using-require">Loading addons using <code>require()</code></a></li> 304</ul> 305</li> 306<li><a href="#native-abstractions-for-nodejs">Native abstractions for Node.js</a></li> 307<li><span class="stability_2"><a href="#node-api">Node-API</a></span></li> 308<li><a href="#addon-examples">Addon examples</a> 309<ul> 310<li><a href="#function-arguments">Function arguments</a></li> 311<li><a href="#callbacks">Callbacks</a></li> 312<li><a href="#object-factory">Object factory</a></li> 313<li><a href="#function-factory">Function factory</a></li> 314<li><a href="#wrapping-c-objects">Wrapping C++ objects</a></li> 315<li><a href="#factory-of-wrapped-objects">Factory of wrapped objects</a></li> 316<li><a href="#passing-wrapped-objects-around">Passing wrapped objects around</a></li> 317</ul> 318</li> 319</ul> 320</li> 321</ul></details> 322 323 <div id="apicontent"> 324 <h2>C++ addons<span><a class="mark" href="#c-addons" id="c-addons">#</a></span><a aria-hidden="true" class="legacy" id="addons_c_addons"></a></h2> 325 326 327<p><em>Addons</em> are dynamically-linked shared objects written in C++. The 328<a href="modules.html#requireid"><code>require()</code></a> function can load addons as ordinary Node.js modules. 329Addons provide an interface between JavaScript and C/C++ libraries.</p> 330<p>There are three options for implementing addons: Node-API, nan, or direct 331use of internal V8, libuv, and Node.js libraries. Unless there is a need for 332direct access to functionality which is not exposed by Node-API, use Node-API. 333Refer to <a href="n-api.html">C/C++ addons with Node-API</a> for more information on 334Node-API.</p> 335<p>When not using Node-API, implementing addons is complicated, 336involving knowledge of several components and APIs:</p> 337<ul> 338<li> 339<p><a href="https://v8.dev/">V8</a>: the C++ library Node.js uses to provide the 340JavaScript implementation. V8 provides the mechanisms for creating objects, 341calling functions, etc. V8's API is documented mostly in the 342<code>v8.h</code> header file (<code>deps/v8/include/v8.h</code> in the Node.js source 343tree), which is also available <a href="https://v8docs.nodesource.com/">online</a>.</p> 344</li> 345<li> 346<p><a href="https://github.com/libuv/libuv">libuv</a>: The C library that implements the Node.js event loop, its worker 347threads and all of the asynchronous behaviors of the platform. It also 348serves as a cross-platform abstraction library, giving easy, POSIX-like 349access across all major operating systems to many common system tasks, such 350as interacting with the file system, sockets, timers, and system events. libuv 351also provides a threading abstraction similar to POSIX threads for 352more sophisticated asynchronous addons that need to move beyond the 353standard event loop. Addon authors should 354avoid blocking the event loop with I/O or other time-intensive tasks by 355offloading work via libuv to non-blocking system operations, worker threads, 356or a custom use of libuv threads.</p> 357</li> 358<li> 359<p>Internal Node.js libraries. Node.js itself exports C++ APIs that addons can 360use, the most important of which is the <code>node::ObjectWrap</code> class.</p> 361</li> 362<li> 363<p>Node.js includes other statically linked libraries including OpenSSL. These 364other libraries are located in the <code>deps/</code> directory in the Node.js source 365tree. Only the libuv, OpenSSL, V8, and zlib symbols are purposefully 366re-exported by Node.js and may be used to various extents by addons. See 367<a href="#linking-to-libraries-included-with-nodejs">Linking to libraries included with Node.js</a> for additional information.</p> 368</li> 369</ul> 370<p>All of the following examples are available for <a href="https://github.com/nodejs/node-addon-examples">download</a> and may 371be used as the starting-point for an addon.</p> 372<section><h3>Hello world<span><a class="mark" href="#hello-world" id="hello-world">#</a></span><a aria-hidden="true" class="legacy" id="addons_hello_world"></a></h3> 373<p>This "Hello world" example is a simple addon, written in C++, that is the 374equivalent of the following JavaScript code:</p> 375<pre><code class="language-js"><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">hello</span> = <span class="hljs-function">() =></span> <span class="hljs-string">'world'</span>;</code> <button class="copy-button">copy</button></pre> 376<p>First, create the file <code>hello.cc</code>:</p> 377<pre><code class="language-cpp"><span class="hljs-comment">// hello.cc</span> 378<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 379 380<span class="hljs-keyword">namespace</span> demo { 381 382<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 383<span class="hljs-keyword">using</span> v8::Isolate; 384<span class="hljs-keyword">using</span> v8::Local; 385<span class="hljs-keyword">using</span> v8::Object; 386<span class="hljs-keyword">using</span> v8::String; 387<span class="hljs-keyword">using</span> v8::Value; 388 389<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Method</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 390 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 391 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(String::<span class="hljs-built_in">NewFromUtf8</span>( 392 isolate, <span class="hljs-string">"world"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 393} 394 395<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Initialize</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 396 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"hello"</span>, Method); 397} 398 399<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Initialize) 400 401} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 402<p>All Node.js addons must export an initialization function following 403the pattern:</p> 404<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Initialize</span><span class="hljs-params">(Local<Object> exports)</span></span>; 405<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Initialize)</code> <button class="copy-button">copy</button></pre> 406<p>There is no semi-colon after <code>NODE_MODULE</code> as it's not a function (see 407<code>node.h</code>).</p> 408<p>The <code>module_name</code> must match the filename of the final binary (excluding 409the <code>.node</code> suffix).</p> 410<p>In the <code>hello.cc</code> example, then, the initialization function is <code>Initialize</code> 411and the addon module name is <code>addon</code>.</p> 412<p>When building addons with <code>node-gyp</code>, using the macro <code>NODE_GYP_MODULE_NAME</code> as 413the first parameter of <code>NODE_MODULE()</code> will ensure that the name of the final 414binary will be passed to <code>NODE_MODULE()</code>.</p> 415<p>Addons defined with <code>NODE_MODULE()</code> can not be loaded in multiple contexts or 416multiple threads at the same time.</p> 417<h4>Context-aware addons<span><a class="mark" href="#context-aware-addons" id="context-aware-addons">#</a></span><a aria-hidden="true" class="legacy" id="addons_context_aware_addons"></a></h4> 418<p>There are environments in which Node.js addons may need to be loaded multiple 419times in multiple contexts. For example, the <a href="https://electronjs.org/">Electron</a> runtime runs multiple 420instances of Node.js in a single process. Each instance will have its own 421<code>require()</code> cache, and thus each instance will need a native addon to behave 422correctly when loaded via <code>require()</code>. This means that the addon 423must support multiple initializations.</p> 424<p>A context-aware addon can be constructed by using the macro 425<code>NODE_MODULE_INITIALIZER</code>, which expands to the name of a function which Node.js 426will expect to find when it loads an addon. An addon can thus be initialized as 427in the following example:</p> 428<pre><code class="language-cpp"><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> v8; 429 430<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function">NODE_MODULE_EXPORT <span class="hljs-type">void</span> 431<span class="hljs-title">NODE_MODULE_INITIALIZER</span><span class="hljs-params">(Local<Object> exports, 432 Local<Value> <span class="hljs-keyword">module</span>, 433 Local<Context> context)</span> </span>{ 434 <span class="hljs-comment">/* Perform addon initialization steps here. */</span> 435}</code> <button class="copy-button">copy</button></pre> 436<p>Another option is to use the macro <code>NODE_MODULE_INIT()</code>, which will also 437construct a context-aware addon. Unlike <code>NODE_MODULE()</code>, which is used to 438construct an addon around a given addon initializer function, 439<code>NODE_MODULE_INIT()</code> serves as the declaration of such an initializer to be 440followed by a function body.</p> 441<p>The following three variables may be used inside the function body following an 442invocation of <code>NODE_MODULE_INIT()</code>:</p> 443<ul> 444<li><code>Local<Object> exports</code>,</li> 445<li><code>Local<Value> module</code>, and</li> 446<li><code>Local<Context> context</code></li> 447</ul> 448<p>The choice to build a context-aware addon carries with it the responsibility of 449carefully managing global static data. Since the addon may be loaded multiple 450times, potentially even from different threads, any global static data stored 451in the addon must be properly protected, and must not contain any persistent 452references to JavaScript objects. The reason for this is that JavaScript 453objects are only valid in one context, and will likely cause a crash when 454accessed from the wrong context or from a different thread than the one on which 455they were created.</p> 456<p>The context-aware addon can be structured to avoid global static data by 457performing the following steps:</p> 458<ul> 459<li>Define a class which will hold per-addon-instance data and which has a static 460member of the form 461<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">DeleteInstance</span><span class="hljs-params">(<span class="hljs-type">void</span>* data)</span> </span>{ 462 <span class="hljs-comment">// Cast `data` to an instance of the class and delete it.</span> 463}</code> <button class="copy-button">copy</button></pre> 464</li> 465<li>Heap-allocate an instance of this class in the addon initializer. This can be 466accomplished using the <code>new</code> keyword.</li> 467<li>Call <code>node::AddEnvironmentCleanupHook()</code>, passing it the above-created 468instance and a pointer to <code>DeleteInstance()</code>. This will ensure the instance is 469deleted when the environment is torn down.</li> 470<li>Store the instance of the class in a <code>v8::External</code>, and</li> 471<li>Pass the <code>v8::External</code> to all methods exposed to JavaScript by passing it 472to <code>v8::FunctionTemplate::New()</code> or <code>v8::Function::New()</code> which creates the 473native-backed JavaScript functions. The third parameter of 474<code>v8::FunctionTemplate::New()</code> or <code>v8::Function::New()</code> accepts the 475<code>v8::External</code> and makes it available in the native callback using the 476<code>v8::FunctionCallbackInfo::Data()</code> method.</li> 477</ul> 478<p>This will ensure that the per-addon-instance data reaches each binding that can 479be called from JavaScript. The per-addon-instance data must also be passed into 480any asynchronous callbacks the addon may create.</p> 481<p>The following example illustrates the implementation of a context-aware addon:</p> 482<pre><code class="language-cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 483 484<span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> v8; 485 486<span class="hljs-keyword">class</span> <span class="hljs-title class_">AddonData</span> { 487 <span class="hljs-keyword">public</span>: 488 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">AddonData</span><span class="hljs-params">(Isolate* isolate)</span>: 489 call_count(<span class="hljs-number">0</span>) {</span> 490 <span class="hljs-comment">// Ensure this per-addon-instance data is deleted at environment cleanup.</span> 491 node::<span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, DeleteInstance, <span class="hljs-keyword">this</span>); 492 } 493 494 <span class="hljs-comment">// Per-addon data.</span> 495 <span class="hljs-type">int</span> call_count; 496 497 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">DeleteInstance</span><span class="hljs-params">(<span class="hljs-type">void</span>* data)</span> </span>{ 498 <span class="hljs-keyword">delete</span> <span class="hljs-built_in">static_cast</span><AddonData*>(data); 499 } 500}; 501 502<span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Method</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& info)</span> </span>{ 503 <span class="hljs-comment">// Retrieve the per-addon-instance data.</span> 504 AddonData* data = 505 <span class="hljs-built_in">reinterpret_cast</span><AddonData*>(info.<span class="hljs-built_in">Data</span>().<span class="hljs-built_in">As</span><External>()-><span class="hljs-built_in">Value</span>()); 506 data->call_count++; 507 info.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>((<span class="hljs-type">double</span>)data->call_count); 508} 509 510<span class="hljs-comment">// Initialize this addon to be context-aware.</span> 511<span class="hljs-built_in">NODE_MODULE_INIT</span>(<span class="hljs-comment">/* exports, module, context */</span>) { 512 Isolate* isolate = context-><span class="hljs-built_in">GetIsolate</span>(); 513 514 <span class="hljs-comment">// Create a new instance of `AddonData` for this instance of the addon and</span> 515 <span class="hljs-comment">// tie its life cycle to that of the Node.js environment.</span> 516 AddonData* data = <span class="hljs-keyword">new</span> <span class="hljs-built_in">AddonData</span>(isolate); 517 518 <span class="hljs-comment">// Wrap the data in a `v8::External` so we can pass it to the method we</span> 519 <span class="hljs-comment">// expose.</span> 520 Local<External> external = External::<span class="hljs-built_in">New</span>(isolate, data); 521 522 <span class="hljs-comment">// Expose the method `Method` to JavaScript, and make sure it receives the</span> 523 <span class="hljs-comment">// per-addon-instance data we created above by passing `external` as the</span> 524 <span class="hljs-comment">// third parameter to the `FunctionTemplate` constructor.</span> 525 exports-><span class="hljs-built_in">Set</span>(context, 526 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"method"</span>).<span class="hljs-built_in">ToLocalChecked</span>(), 527 FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, Method, external) 528 -><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()).<span class="hljs-built_in">FromJust</span>(); 529}</code> <button class="copy-button">copy</button></pre> 530<h5>Worker support<span><a class="mark" href="#worker-support" id="worker-support">#</a></span><a aria-hidden="true" class="legacy" id="addons_worker_support"></a></h5> 531<div class="api_metadata"> 532<details class="changelog"><summary>History</summary> 533<table> 534<tbody><tr><th>Version</th><th>Changes</th></tr> 535<tr><td>v14.8.0, v12.19.0</td> 536<td><p>Cleanup hooks may now be asynchronous.</p></td></tr> 537</tbody></table> 538</details> 539</div> 540<p>In order to be loaded from multiple Node.js environments, 541such as a main thread and a Worker thread, an add-on needs to either:</p> 542<ul> 543<li>Be an Node-API addon, or</li> 544<li>Be declared as context-aware using <code>NODE_MODULE_INIT()</code> as described above</li> 545</ul> 546<p>In order to support <a href="worker_threads.html#class-worker"><code>Worker</code></a> threads, addons need to clean up any resources 547they may have allocated when such a thread exists. This can be achieved through 548the usage of the <code>AddEnvironmentCleanupHook()</code> function:</p> 549<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">AddEnvironmentCleanupHook</span><span class="hljs-params">(v8::Isolate* isolate, 550 <span class="hljs-type">void</span> (*fun)(<span class="hljs-type">void</span>* arg), 551 <span class="hljs-type">void</span>* arg)</span></span>;</code> <button class="copy-button">copy</button></pre> 552<p>This function adds a hook that will run before a given Node.js instance shuts 553down. If necessary, such hooks can be removed before they are run using 554<code>RemoveEnvironmentCleanupHook()</code>, which has the same signature. Callbacks are 555run in last-in first-out order.</p> 556<p>If necessary, there is an additional pair of <code>AddEnvironmentCleanupHook()</code> 557and <code>RemoveEnvironmentCleanupHook()</code> overloads, where the cleanup hook takes a 558callback function. This can be used for shutting down asynchronous resources, 559such as any libuv handles registered by the addon.</p> 560<p>The following <code>addon.cc</code> uses <code>AddEnvironmentCleanupHook</code>:</p> 561<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 562<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 563<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><assert.h></span></span> 564<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span> 565 566<span class="hljs-keyword">using</span> node::AddEnvironmentCleanupHook; 567<span class="hljs-keyword">using</span> v8::HandleScope; 568<span class="hljs-keyword">using</span> v8::Isolate; 569<span class="hljs-keyword">using</span> v8::Local; 570<span class="hljs-keyword">using</span> v8::Object; 571 572<span class="hljs-comment">// Note: In a real-world application, do not rely on static/global data.</span> 573<span class="hljs-type">static</span> <span class="hljs-type">char</span> cookie[] = <span class="hljs-string">"yum yum"</span>; 574<span class="hljs-type">static</span> <span class="hljs-type">int</span> cleanup_cb1_called = <span class="hljs-number">0</span>; 575<span class="hljs-type">static</span> <span class="hljs-type">int</span> cleanup_cb2_called = <span class="hljs-number">0</span>; 576 577<span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">cleanup_cb1</span><span class="hljs-params">(<span class="hljs-type">void</span>* arg)</span> </span>{ 578 Isolate* isolate = <span class="hljs-built_in">static_cast</span><Isolate*>(arg); 579 <span class="hljs-function">HandleScope <span class="hljs-title">scope</span><span class="hljs-params">(isolate)</span></span>; 580 Local<Object> obj = Object::<span class="hljs-built_in">New</span>(isolate); 581 <span class="hljs-built_in">assert</span>(!obj.<span class="hljs-built_in">IsEmpty</span>()); <span class="hljs-comment">// assert VM is still alive</span> 582 <span class="hljs-built_in">assert</span>(obj-><span class="hljs-built_in">IsObject</span>()); 583 cleanup_cb1_called++; 584} 585 586<span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">cleanup_cb2</span><span class="hljs-params">(<span class="hljs-type">void</span>* arg)</span> </span>{ 587 <span class="hljs-built_in">assert</span>(arg == <span class="hljs-built_in">static_cast</span><<span class="hljs-type">void</span>*>(cookie)); 588 cleanup_cb2_called++; 589} 590 591<span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">sanity_check</span><span class="hljs-params">(<span class="hljs-type">void</span>*)</span> </span>{ 592 <span class="hljs-built_in">assert</span>(cleanup_cb1_called == <span class="hljs-number">1</span>); 593 <span class="hljs-built_in">assert</span>(cleanup_cb2_called == <span class="hljs-number">1</span>); 594} 595 596<span class="hljs-comment">// Initialize this addon to be context-aware.</span> 597<span class="hljs-built_in">NODE_MODULE_INIT</span>(<span class="hljs-comment">/* exports, module, context */</span>) { 598 Isolate* isolate = context-><span class="hljs-built_in">GetIsolate</span>(); 599 600 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, sanity_check, <span class="hljs-literal">nullptr</span>); 601 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, cleanup_cb2, cookie); 602 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, cleanup_cb1, isolate); 603}</code> <button class="copy-button">copy</button></pre> 604<p>Test in JavaScript by running:</p> 605<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 606<span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>);</code> <button class="copy-button">copy</button></pre> 607<h4>Building<span><a class="mark" href="#building" id="building">#</a></span><a aria-hidden="true" class="legacy" id="addons_building"></a></h4> 608<p>Once the source code has been written, it must be compiled into the binary 609<code>addon.node</code> file. To do so, create a file called <code>binding.gyp</code> in the 610top-level of the project describing the build configuration of the module 611using a JSON-like format. This file is used by <a href="https://github.com/nodejs/node-gyp">node-gyp</a>, a tool written 612specifically to compile Node.js addons.</p> 613<pre><code class="language-json"><span class="hljs-punctuation">{</span> 614 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 615 <span class="hljs-punctuation">{</span> 616 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 617 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"hello.cc"</span> <span class="hljs-punctuation">]</span> 618 <span class="hljs-punctuation">}</span> 619 <span class="hljs-punctuation">]</span> 620<span class="hljs-punctuation">}</span></code> <button class="copy-button">copy</button></pre> 621<p>A version of the <code>node-gyp</code> utility is bundled and distributed with 622Node.js as part of <code>npm</code>. This version is not made directly available for 623developers to use and is intended only to support the ability to use the 624<code>npm install</code> command to compile and install addons. Developers who wish to 625use <code>node-gyp</code> directly can install it using the command 626<code>npm install -g node-gyp</code>. See the <code>node-gyp</code> <a href="https://github.com/nodejs/node-gyp#installation">installation instructions</a> for 627more information, including platform-specific requirements.</p> 628<p>Once the <code>binding.gyp</code> file has been created, use <code>node-gyp configure</code> to 629generate the appropriate project build files for the current platform. This 630will generate either a <code>Makefile</code> (on Unix platforms) or a <code>vcxproj</code> file 631(on Windows) in the <code>build/</code> directory.</p> 632<p>Next, invoke the <code>node-gyp build</code> command to generate the compiled <code>addon.node</code> 633file. This will be put into the <code>build/Release/</code> directory.</p> 634<p>When using <code>npm install</code> to install a Node.js addon, npm uses its own bundled 635version of <code>node-gyp</code> to perform this same set of actions, generating a 636compiled version of the addon for the user's platform on demand.</p> 637<p>Once built, the binary addon can be used from within Node.js by pointing 638<a href="modules.html#requireid"><code>require()</code></a> to the built <code>addon.node</code> module:</p> 639<pre><code class="language-js"><span class="hljs-comment">// hello.js</span> 640<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 641 642<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(addon.<span class="hljs-title function_">hello</span>()); 643<span class="hljs-comment">// Prints: 'world'</span></code> <button class="copy-button">copy</button></pre> 644<p>Because the exact path to the compiled addon binary can vary depending on how 645it is compiled (i.e. sometimes it may be in <code>./build/Debug/</code>), addons can use 646the <a href="https://github.com/TooTallNate/node-bindings">bindings</a> package to load the compiled module.</p> 647<p>While the <code>bindings</code> package implementation is more sophisticated in how it 648locates addon modules, it is essentially using a <code>try…catch</code> pattern similar to:</p> 649<pre><code class="language-js"><span class="hljs-keyword">try</span> { 650 <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon.node'</span>); 651} <span class="hljs-keyword">catch</span> (err) { 652 <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Debug/addon.node'</span>); 653}</code> <button class="copy-button">copy</button></pre> 654<h4>Linking to libraries included with Node.js<span><a class="mark" href="#linking-to-libraries-included-with-nodejs" id="linking-to-libraries-included-with-nodejs">#</a></span><a aria-hidden="true" class="legacy" id="addons_linking_to_libraries_included_with_node_js"></a></h4> 655<p>Node.js uses statically linked libraries such as V8, libuv, and OpenSSL. All 656addons are required to link to V8 and may link to any of the other dependencies 657as well. Typically, this is as simple as including the appropriate 658<code>#include <...></code> statements (e.g. <code>#include <v8.h></code>) and <code>node-gyp</code> will locate 659the appropriate headers automatically. However, there are a few caveats to be 660aware of:</p> 661<ul> 662<li> 663<p>When <code>node-gyp</code> runs, it will detect the specific release version of Node.js 664and download either the full source tarball or just the headers. If the full 665source is downloaded, addons will have complete access to the full set of 666Node.js dependencies. However, if only the Node.js headers are downloaded, 667then only the symbols exported by Node.js will be available.</p> 668</li> 669<li> 670<p><code>node-gyp</code> can be run using the <code>--nodedir</code> flag pointing at a local Node.js 671source image. Using this option, the addon will have access to the full set of 672dependencies.</p> 673</li> 674</ul> 675<h4>Loading addons using <code>require()</code><span><a class="mark" href="#loading-addons-using-require" id="loading-addons-using-require">#</a></span><a aria-hidden="true" class="legacy" id="addons_loading_addons_using_require"></a></h4> 676<p>The filename extension of the compiled addon binary is <code>.node</code> (as opposed 677to <code>.dll</code> or <code>.so</code>). The <a href="modules.html#requireid"><code>require()</code></a> function is written to look for 678files with the <code>.node</code> file extension and initialize those as dynamically-linked 679libraries.</p> 680<p>When calling <a href="modules.html#requireid"><code>require()</code></a>, the <code>.node</code> extension can usually be 681omitted and Node.js will still find and initialize the addon. One caveat, 682however, is that Node.js will first attempt to locate and load modules or 683JavaScript files that happen to share the same base name. For instance, if 684there is a file <code>addon.js</code> in the same directory as the binary <code>addon.node</code>, 685then <a href="modules.html#requireid"><code>require('addon')</code></a> will give precedence to the <code>addon.js</code> file 686and load it instead.</p> 687</section><section><h3>Native abstractions for Node.js<span><a class="mark" href="#native-abstractions-for-nodejs" id="native-abstractions-for-nodejs">#</a></span><a aria-hidden="true" class="legacy" id="addons_native_abstractions_for_node_js"></a></h3> 688<p>Each of the examples illustrated in this document directly use the 689Node.js and V8 APIs for implementing addons. The V8 API can, and has, changed 690dramatically from one V8 release to the next (and one major Node.js release to 691the next). With each change, addons may need to be updated and recompiled in 692order to continue functioning. The Node.js release schedule is designed to 693minimize the frequency and impact of such changes but there is little that 694Node.js can do to ensure stability of the V8 APIs.</p> 695<p>The <a href="https://github.com/nodejs/nan">Native Abstractions for Node.js</a> (or <code>nan</code>) provide a set of tools that 696addon developers are recommended to use to keep compatibility between past and 697future releases of V8 and Node.js. See the <code>nan</code> <a href="https://github.com/nodejs/nan/tree/HEAD/examples/">examples</a> for an 698illustration of how it can be used.</p> 699</section><section><h3>Node-API<span><a class="mark" href="#node-api" id="node-api">#</a></span><a aria-hidden="true" class="legacy" id="addons_node_api"></a></h3> 700<p></p><div class="api_stability api_stability_2"><a href="documentation.html#stability-index">Stability: 2</a> - Stable</div><p></p> 701<p>Node-API is an API for building native addons. It is independent from 702the underlying JavaScript runtime (e.g. V8) and is maintained as part of 703Node.js itself. This API will be Application Binary Interface (ABI) stable 704across versions of Node.js. It is intended to insulate addons from 705changes in the underlying JavaScript engine and allow modules 706compiled for one version to run on later versions of Node.js without 707recompilation. Addons are built/packaged with the same approach/tools 708outlined in this document (node-gyp, etc.). The only difference is the 709set of APIs that are used by the native code. Instead of using the V8 710or <a href="https://github.com/nodejs/nan">Native Abstractions for Node.js</a> APIs, the functions available 711in the Node-API are used.</p> 712<p>Creating and maintaining an addon that benefits from the ABI stability 713provided by Node-API carries with it certain 714<a href="n-api.html#implications-of-abi-stability">implementation considerations</a>.</p> 715<p>To use Node-API in the above "Hello world" example, replace the content of 716<code>hello.cc</code> with the following. All other instructions remain the same.</p> 717<pre><code class="language-cpp"><span class="hljs-comment">// hello.cc using Node-API</span> 718<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_api.h></span></span> 719 720<span class="hljs-keyword">namespace</span> demo { 721 722<span class="hljs-function">napi_value <span class="hljs-title">Method</span><span class="hljs-params">(napi_env env, napi_callback_info args)</span> </span>{ 723 napi_value greeting; 724 napi_status status; 725 726 status = <span class="hljs-built_in">napi_create_string_utf8</span>(env, <span class="hljs-string">"world"</span>, NAPI_AUTO_LENGTH, &greeting); 727 <span class="hljs-keyword">if</span> (status != napi_ok) <span class="hljs-keyword">return</span> <span class="hljs-literal">nullptr</span>; 728 <span class="hljs-keyword">return</span> greeting; 729} 730 731<span class="hljs-function">napi_value <span class="hljs-title">init</span><span class="hljs-params">(napi_env env, napi_value exports)</span> </span>{ 732 napi_status status; 733 napi_value fn; 734 735 status = <span class="hljs-built_in">napi_create_function</span>(env, <span class="hljs-literal">nullptr</span>, <span class="hljs-number">0</span>, Method, <span class="hljs-literal">nullptr</span>, &fn); 736 <span class="hljs-keyword">if</span> (status != napi_ok) <span class="hljs-keyword">return</span> <span class="hljs-literal">nullptr</span>; 737 738 status = <span class="hljs-built_in">napi_set_named_property</span>(env, exports, <span class="hljs-string">"hello"</span>, fn); 739 <span class="hljs-keyword">if</span> (status != napi_ok) <span class="hljs-keyword">return</span> <span class="hljs-literal">nullptr</span>; 740 <span class="hljs-keyword">return</span> exports; 741} 742 743<span class="hljs-built_in">NAPI_MODULE</span>(NODE_GYP_MODULE_NAME, init) 744 745} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 746<p>The functions available and how to use them are documented in 747<a href="n-api.html">C/C++ addons with Node-API</a>.</p> 748</section><section><h3>Addon examples<span><a class="mark" href="#addon-examples" id="addon-examples">#</a></span><a aria-hidden="true" class="legacy" id="addons_addon_examples"></a></h3> 749<p>Following are some example addons intended to help developers get started. The 750examples use the V8 APIs. Refer to the online <a href="https://v8docs.nodesource.com/">V8 reference</a> 751for help with the various V8 calls, and V8's <a href="https://v8.dev/docs/embed">Embedder's Guide</a> for an 752explanation of several concepts used such as handles, scopes, function 753templates, etc.</p> 754<p>Each of these examples using the following <code>binding.gyp</code> file:</p> 755<pre><code class="language-json"><span class="hljs-punctuation">{</span> 756 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 757 <span class="hljs-punctuation">{</span> 758 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 759 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"addon.cc"</span> <span class="hljs-punctuation">]</span> 760 <span class="hljs-punctuation">}</span> 761 <span class="hljs-punctuation">]</span> 762<span class="hljs-punctuation">}</span></code> <button class="copy-button">copy</button></pre> 763<p>In cases where there is more than one <code>.cc</code> file, simply add the additional 764filename to the <code>sources</code> array:</p> 765<pre><code class="language-json"><span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"addon.cc"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"myexample.cc"</span><span class="hljs-punctuation">]</span></code> <button class="copy-button">copy</button></pre> 766<p>Once the <code>binding.gyp</code> file is ready, the example addons can be configured and 767built using <code>node-gyp</code>:</p> 768<pre><code class="language-console"><span class="hljs-meta prompt_">$ </span><span class="language-bash">node-gyp configure build</span></code> <button class="copy-button">copy</button></pre> 769<h4>Function arguments<span><a class="mark" href="#function-arguments" id="function-arguments">#</a></span><a aria-hidden="true" class="legacy" id="addons_function_arguments"></a></h4> 770<p>Addons will typically expose objects and functions that can be accessed from 771JavaScript running within Node.js. When functions are invoked from JavaScript, 772the input arguments and return value must be mapped to and from the C/C++ 773code.</p> 774<p>The following example illustrates how to read function arguments passed from 775JavaScript and how to return a result:</p> 776<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 777<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 778 779<span class="hljs-keyword">namespace</span> demo { 780 781<span class="hljs-keyword">using</span> v8::Exception; 782<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 783<span class="hljs-keyword">using</span> v8::Isolate; 784<span class="hljs-keyword">using</span> v8::Local; 785<span class="hljs-keyword">using</span> v8::Number; 786<span class="hljs-keyword">using</span> v8::Object; 787<span class="hljs-keyword">using</span> v8::String; 788<span class="hljs-keyword">using</span> v8::Value; 789 790<span class="hljs-comment">// This is the implementation of the "add" method</span> 791<span class="hljs-comment">// Input arguments are passed using the</span> 792<span class="hljs-comment">// const FunctionCallbackInfo<Value>& args struct</span> 793<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Add</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 794 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 795 796 <span class="hljs-comment">// Check the number of arguments passed.</span> 797 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">Length</span>() < <span class="hljs-number">2</span>) { 798 <span class="hljs-comment">// Throw an Error that is passed back to JavaScript</span> 799 isolate-><span class="hljs-built_in">ThrowException</span>(Exception::<span class="hljs-built_in">TypeError</span>( 800 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 801 <span class="hljs-string">"Wrong number of arguments"</span>).<span class="hljs-built_in">ToLocalChecked</span>())); 802 <span class="hljs-keyword">return</span>; 803 } 804 805 <span class="hljs-comment">// Check the argument types</span> 806 <span class="hljs-keyword">if</span> (!args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsNumber</span>() || !args[<span class="hljs-number">1</span>]-><span class="hljs-built_in">IsNumber</span>()) { 807 isolate-><span class="hljs-built_in">ThrowException</span>(Exception::<span class="hljs-built_in">TypeError</span>( 808 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 809 <span class="hljs-string">"Wrong arguments"</span>).<span class="hljs-built_in">ToLocalChecked</span>())); 810 <span class="hljs-keyword">return</span>; 811 } 812 813 <span class="hljs-comment">// Perform the operation</span> 814 <span class="hljs-type">double</span> value = 815 args[<span class="hljs-number">0</span>].<span class="hljs-built_in">As</span><Number>()-><span class="hljs-built_in">Value</span>() + args[<span class="hljs-number">1</span>].<span class="hljs-built_in">As</span><Number>()-><span class="hljs-built_in">Value</span>(); 816 Local<Number> num = Number::<span class="hljs-built_in">New</span>(isolate, value); 817 818 <span class="hljs-comment">// Set the return value (using the passed in</span> 819 <span class="hljs-comment">// FunctionCallbackInfo<Value>&)</span> 820 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(num); 821} 822 823<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 824 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"add"</span>, Add); 825} 826 827<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 828 829} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 830<p>Once compiled, the example addon can be required and used from within Node.js:</p> 831<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 832<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 833 834<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'This should be eight:'</span>, addon.<span class="hljs-title function_">add</span>(<span class="hljs-number">3</span>, <span class="hljs-number">5</span>));</code> <button class="copy-button">copy</button></pre> 835<h4>Callbacks<span><a class="mark" href="#callbacks" id="callbacks">#</a></span><a aria-hidden="true" class="legacy" id="addons_callbacks"></a></h4> 836<p>It is common practice within addons to pass JavaScript functions to a C++ 837function and execute them from there. The following example illustrates how 838to invoke such callbacks:</p> 839<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 840<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 841 842<span class="hljs-keyword">namespace</span> demo { 843 844<span class="hljs-keyword">using</span> v8::Context; 845<span class="hljs-keyword">using</span> v8::Function; 846<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 847<span class="hljs-keyword">using</span> v8::Isolate; 848<span class="hljs-keyword">using</span> v8::Local; 849<span class="hljs-keyword">using</span> v8::Null; 850<span class="hljs-keyword">using</span> v8::Object; 851<span class="hljs-keyword">using</span> v8::String; 852<span class="hljs-keyword">using</span> v8::Value; 853 854<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">RunCallback</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 855 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 856 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 857 Local<Function> cb = Local<Function>::<span class="hljs-built_in">Cast</span>(args[<span class="hljs-number">0</span>]); 858 <span class="hljs-type">const</span> <span class="hljs-type">unsigned</span> argc = <span class="hljs-number">1</span>; 859 Local<Value> argv[argc] = { 860 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 861 <span class="hljs-string">"hello world"</span>).<span class="hljs-built_in">ToLocalChecked</span>() }; 862 cb-><span class="hljs-built_in">Call</span>(context, <span class="hljs-built_in">Null</span>(isolate), argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 863} 864 865<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 866 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, RunCallback); 867} 868 869<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 870 871} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 872<p>This example uses a two-argument form of <code>Init()</code> that receives the full 873<code>module</code> object as the second argument. This allows the addon to completely 874overwrite <code>exports</code> with a single function instead of adding the function as a 875property of <code>exports</code>.</p> 876<p>To test it, run the following JavaScript:</p> 877<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 878<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 879 880<span class="hljs-title function_">addon</span>(<span class="hljs-function">(<span class="hljs-params">msg</span>) =></span> { 881 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(msg); 882<span class="hljs-comment">// Prints: 'hello world'</span> 883});</code> <button class="copy-button">copy</button></pre> 884<p>In this example, the callback function is invoked synchronously.</p> 885<h4>Object factory<span><a class="mark" href="#object-factory" id="object-factory">#</a></span><a aria-hidden="true" class="legacy" id="addons_object_factory"></a></h4> 886<p>Addons can create and return new objects from within a C++ function as 887illustrated in the following example. An object is created and returned with a 888property <code>msg</code> that echoes the string passed to <code>createObject()</code>:</p> 889<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 890<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 891 892<span class="hljs-keyword">namespace</span> demo { 893 894<span class="hljs-keyword">using</span> v8::Context; 895<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 896<span class="hljs-keyword">using</span> v8::Isolate; 897<span class="hljs-keyword">using</span> v8::Local; 898<span class="hljs-keyword">using</span> v8::Object; 899<span class="hljs-keyword">using</span> v8::String; 900<span class="hljs-keyword">using</span> v8::Value; 901 902<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateObject</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 903 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 904 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 905 906 Local<Object> obj = Object::<span class="hljs-built_in">New</span>(isolate); 907 obj-><span class="hljs-built_in">Set</span>(context, 908 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 909 <span class="hljs-string">"msg"</span>).<span class="hljs-built_in">ToLocalChecked</span>(), 910 args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">ToString</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()) 911 .<span class="hljs-built_in">FromJust</span>(); 912 913 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(obj); 914} 915 916<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 917 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, CreateObject); 918} 919 920<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 921 922} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 923<p>To test it in JavaScript:</p> 924<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 925<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 926 927<span class="hljs-keyword">const</span> obj1 = <span class="hljs-title function_">addon</span>(<span class="hljs-string">'hello'</span>); 928<span class="hljs-keyword">const</span> obj2 = <span class="hljs-title function_">addon</span>(<span class="hljs-string">'world'</span>); 929<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj1.<span class="hljs-property">msg</span>, obj2.<span class="hljs-property">msg</span>); 930<span class="hljs-comment">// Prints: 'hello world'</span></code> <button class="copy-button">copy</button></pre> 931<h4>Function factory<span><a class="mark" href="#function-factory" id="function-factory">#</a></span><a aria-hidden="true" class="legacy" id="addons_function_factory"></a></h4> 932<p>Another common scenario is creating JavaScript functions that wrap C++ 933functions and returning those back to JavaScript:</p> 934<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 935<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 936 937<span class="hljs-keyword">namespace</span> demo { 938 939<span class="hljs-keyword">using</span> v8::Context; 940<span class="hljs-keyword">using</span> v8::Function; 941<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 942<span class="hljs-keyword">using</span> v8::FunctionTemplate; 943<span class="hljs-keyword">using</span> v8::Isolate; 944<span class="hljs-keyword">using</span> v8::Local; 945<span class="hljs-keyword">using</span> v8::Object; 946<span class="hljs-keyword">using</span> v8::String; 947<span class="hljs-keyword">using</span> v8::Value; 948 949<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyFunction</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 950 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 951 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(String::<span class="hljs-built_in">NewFromUtf8</span>( 952 isolate, <span class="hljs-string">"hello world"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 953} 954 955<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateFunction</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 956 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 957 958 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 959 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, MyFunction); 960 Local<Function> fn = tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>(); 961 962 <span class="hljs-comment">// omit this to make it anonymous</span> 963 fn-><span class="hljs-built_in">SetName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>( 964 isolate, <span class="hljs-string">"theFunction"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 965 966 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(fn); 967} 968 969<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 970 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, CreateFunction); 971} 972 973<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 974 975} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 976<p>To test:</p> 977<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 978<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 979 980<span class="hljs-keyword">const</span> fn = <span class="hljs-title function_">addon</span>(); 981<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">fn</span>()); 982<span class="hljs-comment">// Prints: 'hello world'</span></code> <button class="copy-button">copy</button></pre> 983<h4>Wrapping C++ objects<span><a class="mark" href="#wrapping-c-objects" id="wrapping-c-objects">#</a></span><a aria-hidden="true" class="legacy" id="addons_wrapping_c_objects"></a></h4> 984<p>It is also possible to wrap C++ objects/classes in a way that allows new 985instances to be created using the JavaScript <code>new</code> operator:</p> 986<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 987<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 988<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 989 990<span class="hljs-keyword">namespace</span> demo { 991 992<span class="hljs-keyword">using</span> v8::Local; 993<span class="hljs-keyword">using</span> v8::Object; 994 995<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitAll</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 996 MyObject::<span class="hljs-built_in">Init</span>(exports); 997} 998 999<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, InitAll) 1000 1001} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 1002<p>Then, in <code>myobject.h</code>, the wrapper class inherits from <code>node::ObjectWrap</code>:</p> 1003<pre><code class="language-cpp"><span class="hljs-comment">// myobject.h</span> 1004<span class="hljs-meta">#<span class="hljs-keyword">ifndef</span> MYOBJECT_H</span> 1005<span class="hljs-meta">#<span class="hljs-keyword">define</span> MYOBJECT_H</span> 1006 1007<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1008<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 1009 1010<span class="hljs-keyword">namespace</span> demo { 1011 1012<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyObject</span> : <span class="hljs-keyword">public</span> node::ObjectWrap { 1013 <span class="hljs-keyword">public</span>: 1014 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(v8::Local<v8::Object> exports)</span></span>; 1015 1016 <span class="hljs-keyword">private</span>: 1017 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">MyObject</span><span class="hljs-params">(<span class="hljs-type">double</span> value = <span class="hljs-number">0</span>)</span></span>; 1018 ~<span class="hljs-built_in">MyObject</span>(); 1019 1020 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">New</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1021 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">PlusOne</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1022 1023 <span class="hljs-type">double</span> value_; 1024}; 1025 1026} <span class="hljs-comment">// namespace demo</span> 1027 1028<span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></code> <button class="copy-button">copy</button></pre> 1029<p>In <code>myobject.cc</code>, implement the various methods that are to be exposed. 1030Below, the method <code>plusOne()</code> is exposed by adding it to the constructor's 1031prototype:</p> 1032<pre><code class="language-cpp"><span class="hljs-comment">// myobject.cc</span> 1033<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1034 1035<span class="hljs-keyword">namespace</span> demo { 1036 1037<span class="hljs-keyword">using</span> v8::Context; 1038<span class="hljs-keyword">using</span> v8::Function; 1039<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1040<span class="hljs-keyword">using</span> v8::FunctionTemplate; 1041<span class="hljs-keyword">using</span> v8::Isolate; 1042<span class="hljs-keyword">using</span> v8::Local; 1043<span class="hljs-keyword">using</span> v8::Number; 1044<span class="hljs-keyword">using</span> v8::Object; 1045<span class="hljs-keyword">using</span> v8::ObjectTemplate; 1046<span class="hljs-keyword">using</span> v8::String; 1047<span class="hljs-keyword">using</span> v8::Value; 1048 1049MyObject::<span class="hljs-built_in">MyObject</span>(<span class="hljs-type">double</span> value) : <span class="hljs-built_in">value_</span>(value) { 1050} 1051 1052MyObject::~<span class="hljs-built_in">MyObject</span>() { 1053} 1054 1055<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::Init</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 1056 Isolate* isolate = exports-><span class="hljs-built_in">GetIsolate</span>(); 1057 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1058 1059 Local<ObjectTemplate> addon_data_tpl = ObjectTemplate::<span class="hljs-built_in">New</span>(isolate); 1060 addon_data_tpl-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); <span class="hljs-comment">// 1 field for the MyObject::New()</span> 1061 Local<Object> addon_data = 1062 addon_data_tpl-><span class="hljs-built_in">NewInstance</span>(context).<span class="hljs-built_in">ToLocalChecked</span>(); 1063 1064 <span class="hljs-comment">// Prepare constructor template</span> 1065 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, New, addon_data); 1066 tpl-><span class="hljs-built_in">SetClassName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 1067 tpl-><span class="hljs-built_in">InstanceTemplate</span>()-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); 1068 1069 <span class="hljs-comment">// Prototype</span> 1070 <span class="hljs-built_in">NODE_SET_PROTOTYPE_METHOD</span>(tpl, <span class="hljs-string">"plusOne"</span>, PlusOne); 1071 1072 Local<Function> constructor = tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>(); 1073 addon_data-><span class="hljs-built_in">SetInternalField</span>(<span class="hljs-number">0</span>, constructor); 1074 exports-><span class="hljs-built_in">Set</span>(context, String::<span class="hljs-built_in">NewFromUtf8</span>( 1075 isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>(), 1076 constructor).<span class="hljs-built_in">FromJust</span>(); 1077} 1078 1079<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::New</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1080 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1081 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1082 1083 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">IsConstructCall</span>()) { 1084 <span class="hljs-comment">// Invoked as constructor: `new MyObject(...)`</span> 1085 <span class="hljs-type">double</span> value = args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsUndefined</span>() ? 1086 <span class="hljs-number">0</span> : args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">NumberValue</span>(context).<span class="hljs-built_in">FromMaybe</span>(<span class="hljs-number">0</span>); 1087 MyObject* obj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">MyObject</span>(value); 1088 obj-><span class="hljs-built_in">Wrap</span>(args.<span class="hljs-built_in">This</span>()); 1089 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(args.<span class="hljs-built_in">This</span>()); 1090 } <span class="hljs-keyword">else</span> { 1091 <span class="hljs-comment">// Invoked as plain function `MyObject(...)`, turn into construct call.</span> 1092 <span class="hljs-type">const</span> <span class="hljs-type">int</span> argc = <span class="hljs-number">1</span>; 1093 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1094 Local<Function> cons = 1095 args.<span class="hljs-built_in">Data</span>().<span class="hljs-built_in">As</span><Object>()-><span class="hljs-built_in">GetInternalField</span>(<span class="hljs-number">0</span>).<span class="hljs-built_in">As</span><Function>(); 1096 Local<Object> result = 1097 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1098 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(result); 1099 } 1100} 1101 1102<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::PlusOne</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1103 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1104 1105 MyObject* obj = ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>(args.<span class="hljs-built_in">Holder</span>()); 1106 obj->value_ += <span class="hljs-number">1</span>; 1107 1108 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(Number::<span class="hljs-built_in">New</span>(isolate, obj->value_)); 1109} 1110 1111} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 1112<p>To build this example, the <code>myobject.cc</code> file must be added to the 1113<code>binding.gyp</code>:</p> 1114<pre><code class="language-json"><span class="hljs-punctuation">{</span> 1115 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 1116 <span class="hljs-punctuation">{</span> 1117 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 1118 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 1119 <span class="hljs-string">"addon.cc"</span><span class="hljs-punctuation">,</span> 1120 <span class="hljs-string">"myobject.cc"</span> 1121 <span class="hljs-punctuation">]</span> 1122 <span class="hljs-punctuation">}</span> 1123 <span class="hljs-punctuation">]</span> 1124<span class="hljs-punctuation">}</span></code> <button class="copy-button">copy</button></pre> 1125<p>Test it with:</p> 1126<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 1127<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 1128 1129<span class="hljs-keyword">const</span> obj = <span class="hljs-keyword">new</span> addon.<span class="hljs-title class_">MyObject</span>(<span class="hljs-number">10</span>); 1130<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1131<span class="hljs-comment">// Prints: 11</span> 1132<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1133<span class="hljs-comment">// Prints: 12</span> 1134<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1135<span class="hljs-comment">// Prints: 13</span></code> <button class="copy-button">copy</button></pre> 1136<p>The destructor for a wrapper object will run when the object is 1137garbage-collected. For destructor testing, there are command-line flags that 1138can be used to make it possible to force garbage collection. These flags are 1139provided by the underlying V8 JavaScript engine. They are subject to change 1140or removal at any time. They are not documented by Node.js or V8, and they 1141should never be used outside of testing.</p> 1142<p>During shutdown of the process or worker threads destructors are not called 1143by the JS engine. Therefore it's the responsibility of the user to track 1144these objects and ensure proper destruction to avoid resource leaks.</p> 1145<h4>Factory of wrapped objects<span><a class="mark" href="#factory-of-wrapped-objects" id="factory-of-wrapped-objects">#</a></span><a aria-hidden="true" class="legacy" id="addons_factory_of_wrapped_objects"></a></h4> 1146<p>Alternatively, it is possible to use a factory pattern to avoid explicitly 1147creating object instances using the JavaScript <code>new</code> operator:</p> 1148<pre><code class="language-js"><span class="hljs-keyword">const</span> obj = addon.<span class="hljs-title function_">createObject</span>(); 1149<span class="hljs-comment">// instead of:</span> 1150<span class="hljs-comment">// const obj = new addon.Object();</span></code> <button class="copy-button">copy</button></pre> 1151<p>First, the <code>createObject()</code> method is implemented in <code>addon.cc</code>:</p> 1152<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 1153<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1154<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1155 1156<span class="hljs-keyword">namespace</span> demo { 1157 1158<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1159<span class="hljs-keyword">using</span> v8::Isolate; 1160<span class="hljs-keyword">using</span> v8::Local; 1161<span class="hljs-keyword">using</span> v8::Object; 1162<span class="hljs-keyword">using</span> v8::String; 1163<span class="hljs-keyword">using</span> v8::Value; 1164 1165<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateObject</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1166 MyObject::<span class="hljs-built_in">NewInstance</span>(args); 1167} 1168 1169<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitAll</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 1170 MyObject::<span class="hljs-built_in">Init</span>(exports-><span class="hljs-built_in">GetIsolate</span>()); 1171 1172 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, CreateObject); 1173} 1174 1175<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, InitAll) 1176 1177} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 1178<p>In <code>myobject.h</code>, the static method <code>NewInstance()</code> is added to handle 1179instantiating the object. This method takes the place of using <code>new</code> in 1180JavaScript:</p> 1181<pre><code class="language-cpp"><span class="hljs-comment">// myobject.h</span> 1182<span class="hljs-meta">#<span class="hljs-keyword">ifndef</span> MYOBJECT_H</span> 1183<span class="hljs-meta">#<span class="hljs-keyword">define</span> MYOBJECT_H</span> 1184 1185<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1186<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 1187 1188<span class="hljs-keyword">namespace</span> demo { 1189 1190<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyObject</span> : <span class="hljs-keyword">public</span> node::ObjectWrap { 1191 <span class="hljs-keyword">public</span>: 1192 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(v8::Isolate* isolate)</span></span>; 1193 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">NewInstance</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1194 1195 <span class="hljs-keyword">private</span>: 1196 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">MyObject</span><span class="hljs-params">(<span class="hljs-type">double</span> value = <span class="hljs-number">0</span>)</span></span>; 1197 ~<span class="hljs-built_in">MyObject</span>(); 1198 1199 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">New</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1200 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">PlusOne</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1201 <span class="hljs-type">static</span> v8::Global<v8::Function> constructor; 1202 <span class="hljs-type">double</span> value_; 1203}; 1204 1205} <span class="hljs-comment">// namespace demo</span> 1206 1207<span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></code> <button class="copy-button">copy</button></pre> 1208<p>The implementation in <code>myobject.cc</code> is similar to the previous example:</p> 1209<pre><code class="language-cpp"><span class="hljs-comment">// myobject.cc</span> 1210<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1211<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1212 1213<span class="hljs-keyword">namespace</span> demo { 1214 1215<span class="hljs-keyword">using</span> node::AddEnvironmentCleanupHook; 1216<span class="hljs-keyword">using</span> v8::Context; 1217<span class="hljs-keyword">using</span> v8::Function; 1218<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1219<span class="hljs-keyword">using</span> v8::FunctionTemplate; 1220<span class="hljs-keyword">using</span> v8::Global; 1221<span class="hljs-keyword">using</span> v8::Isolate; 1222<span class="hljs-keyword">using</span> v8::Local; 1223<span class="hljs-keyword">using</span> v8::Number; 1224<span class="hljs-keyword">using</span> v8::Object; 1225<span class="hljs-keyword">using</span> v8::String; 1226<span class="hljs-keyword">using</span> v8::Value; 1227 1228<span class="hljs-comment">// Warning! This is not thread-safe, this addon cannot be used for worker</span> 1229<span class="hljs-comment">// threads.</span> 1230Global<Function> MyObject::constructor; 1231 1232MyObject::<span class="hljs-built_in">MyObject</span>(<span class="hljs-type">double</span> value) : <span class="hljs-built_in">value_</span>(value) { 1233} 1234 1235MyObject::~<span class="hljs-built_in">MyObject</span>() { 1236} 1237 1238<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::Init</span><span class="hljs-params">(Isolate* isolate)</span> </span>{ 1239 <span class="hljs-comment">// Prepare constructor template</span> 1240 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, New); 1241 tpl-><span class="hljs-built_in">SetClassName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 1242 tpl-><span class="hljs-built_in">InstanceTemplate</span>()-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); 1243 1244 <span class="hljs-comment">// Prototype</span> 1245 <span class="hljs-built_in">NODE_SET_PROTOTYPE_METHOD</span>(tpl, <span class="hljs-string">"plusOne"</span>, PlusOne); 1246 1247 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1248 constructor.<span class="hljs-built_in">Reset</span>(isolate, tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1249 1250 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, [](<span class="hljs-type">void</span>*) { 1251 constructor.<span class="hljs-built_in">Reset</span>(); 1252 }, <span class="hljs-literal">nullptr</span>); 1253} 1254 1255<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::New</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1256 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1257 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1258 1259 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">IsConstructCall</span>()) { 1260 <span class="hljs-comment">// Invoked as constructor: `new MyObject(...)`</span> 1261 <span class="hljs-type">double</span> value = args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsUndefined</span>() ? 1262 <span class="hljs-number">0</span> : args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">NumberValue</span>(context).<span class="hljs-built_in">FromMaybe</span>(<span class="hljs-number">0</span>); 1263 MyObject* obj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">MyObject</span>(value); 1264 obj-><span class="hljs-built_in">Wrap</span>(args.<span class="hljs-built_in">This</span>()); 1265 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(args.<span class="hljs-built_in">This</span>()); 1266 } <span class="hljs-keyword">else</span> { 1267 <span class="hljs-comment">// Invoked as plain function `MyObject(...)`, turn into construct call.</span> 1268 <span class="hljs-type">const</span> <span class="hljs-type">int</span> argc = <span class="hljs-number">1</span>; 1269 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1270 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1271 Local<Object> instance = 1272 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1273 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1274 } 1275} 1276 1277<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::NewInstance</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1278 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1279 1280 <span class="hljs-type">const</span> <span class="hljs-type">unsigned</span> argc = <span class="hljs-number">1</span>; 1281 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1282 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1283 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1284 Local<Object> instance = 1285 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1286 1287 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1288} 1289 1290<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::PlusOne</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1291 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1292 1293 MyObject* obj = ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>(args.<span class="hljs-built_in">Holder</span>()); 1294 obj->value_ += <span class="hljs-number">1</span>; 1295 1296 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(Number::<span class="hljs-built_in">New</span>(isolate, obj->value_)); 1297} 1298 1299} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 1300<p>Once again, to build this example, the <code>myobject.cc</code> file must be added to the 1301<code>binding.gyp</code>:</p> 1302<pre><code class="language-json"><span class="hljs-punctuation">{</span> 1303 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 1304 <span class="hljs-punctuation">{</span> 1305 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 1306 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 1307 <span class="hljs-string">"addon.cc"</span><span class="hljs-punctuation">,</span> 1308 <span class="hljs-string">"myobject.cc"</span> 1309 <span class="hljs-punctuation">]</span> 1310 <span class="hljs-punctuation">}</span> 1311 <span class="hljs-punctuation">]</span> 1312<span class="hljs-punctuation">}</span></code> <button class="copy-button">copy</button></pre> 1313<p>Test it with:</p> 1314<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 1315<span class="hljs-keyword">const</span> createObject = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 1316 1317<span class="hljs-keyword">const</span> obj = <span class="hljs-title function_">createObject</span>(<span class="hljs-number">10</span>); 1318<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1319<span class="hljs-comment">// Prints: 11</span> 1320<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1321<span class="hljs-comment">// Prints: 12</span> 1322<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1323<span class="hljs-comment">// Prints: 13</span> 1324 1325<span class="hljs-keyword">const</span> obj2 = <span class="hljs-title function_">createObject</span>(<span class="hljs-number">20</span>); 1326<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj2.<span class="hljs-title function_">plusOne</span>()); 1327<span class="hljs-comment">// Prints: 21</span> 1328<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj2.<span class="hljs-title function_">plusOne</span>()); 1329<span class="hljs-comment">// Prints: 22</span> 1330<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj2.<span class="hljs-title function_">plusOne</span>()); 1331<span class="hljs-comment">// Prints: 23</span></code> <button class="copy-button">copy</button></pre> 1332<h4>Passing wrapped objects around<span><a class="mark" href="#passing-wrapped-objects-around" id="passing-wrapped-objects-around">#</a></span><a aria-hidden="true" class="legacy" id="addons_passing_wrapped_objects_around"></a></h4> 1333<p>In addition to wrapping and returning C++ objects, it is possible to pass 1334wrapped objects around by unwrapping them with the Node.js helper function 1335<code>node::ObjectWrap::Unwrap</code>. The following examples shows a function <code>add()</code> 1336that can take two <code>MyObject</code> objects as input arguments:</p> 1337<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 1338<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1339<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 1340<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1341 1342<span class="hljs-keyword">namespace</span> demo { 1343 1344<span class="hljs-keyword">using</span> v8::Context; 1345<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1346<span class="hljs-keyword">using</span> v8::Isolate; 1347<span class="hljs-keyword">using</span> v8::Local; 1348<span class="hljs-keyword">using</span> v8::Number; 1349<span class="hljs-keyword">using</span> v8::Object; 1350<span class="hljs-keyword">using</span> v8::String; 1351<span class="hljs-keyword">using</span> v8::Value; 1352 1353<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateObject</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1354 MyObject::<span class="hljs-built_in">NewInstance</span>(args); 1355} 1356 1357<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Add</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1358 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1359 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1360 1361 MyObject* obj1 = node::ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>( 1362 args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">ToObject</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1363 MyObject* obj2 = node::ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>( 1364 args[<span class="hljs-number">1</span>]-><span class="hljs-built_in">ToObject</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1365 1366 <span class="hljs-type">double</span> sum = obj1-><span class="hljs-built_in">value</span>() + obj2-><span class="hljs-built_in">value</span>(); 1367 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(Number::<span class="hljs-built_in">New</span>(isolate, sum)); 1368} 1369 1370<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitAll</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 1371 MyObject::<span class="hljs-built_in">Init</span>(exports-><span class="hljs-built_in">GetIsolate</span>()); 1372 1373 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"createObject"</span>, CreateObject); 1374 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"add"</span>, Add); 1375} 1376 1377<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, InitAll) 1378 1379} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 1380<p>In <code>myobject.h</code>, a new public method is added to allow access to private values 1381after unwrapping the object.</p> 1382<pre><code class="language-cpp"><span class="hljs-comment">// myobject.h</span> 1383<span class="hljs-meta">#<span class="hljs-keyword">ifndef</span> MYOBJECT_H</span> 1384<span class="hljs-meta">#<span class="hljs-keyword">define</span> MYOBJECT_H</span> 1385 1386<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1387<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 1388 1389<span class="hljs-keyword">namespace</span> demo { 1390 1391<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyObject</span> : <span class="hljs-keyword">public</span> node::ObjectWrap { 1392 <span class="hljs-keyword">public</span>: 1393 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(v8::Isolate* isolate)</span></span>; 1394 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">NewInstance</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1395 <span class="hljs-function"><span class="hljs-keyword">inline</span> <span class="hljs-type">double</span> <span class="hljs-title">value</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>{ <span class="hljs-keyword">return</span> value_; } 1396 1397 <span class="hljs-keyword">private</span>: 1398 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">MyObject</span><span class="hljs-params">(<span class="hljs-type">double</span> value = <span class="hljs-number">0</span>)</span></span>; 1399 ~<span class="hljs-built_in">MyObject</span>(); 1400 1401 <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">New</span><span class="hljs-params">(<span class="hljs-type">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1402 <span class="hljs-type">static</span> v8::Global<v8::Function> constructor; 1403 <span class="hljs-type">double</span> value_; 1404}; 1405 1406} <span class="hljs-comment">// namespace demo</span> 1407 1408<span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></code> <button class="copy-button">copy</button></pre> 1409<p>The implementation of <code>myobject.cc</code> is similar to before:</p> 1410<pre><code class="language-cpp"><span class="hljs-comment">// myobject.cc</span> 1411<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1412<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1413 1414<span class="hljs-keyword">namespace</span> demo { 1415 1416<span class="hljs-keyword">using</span> node::AddEnvironmentCleanupHook; 1417<span class="hljs-keyword">using</span> v8::Context; 1418<span class="hljs-keyword">using</span> v8::Function; 1419<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1420<span class="hljs-keyword">using</span> v8::FunctionTemplate; 1421<span class="hljs-keyword">using</span> v8::Global; 1422<span class="hljs-keyword">using</span> v8::Isolate; 1423<span class="hljs-keyword">using</span> v8::Local; 1424<span class="hljs-keyword">using</span> v8::Object; 1425<span class="hljs-keyword">using</span> v8::String; 1426<span class="hljs-keyword">using</span> v8::Value; 1427 1428<span class="hljs-comment">// Warning! This is not thread-safe, this addon cannot be used for worker</span> 1429<span class="hljs-comment">// threads.</span> 1430Global<Function> MyObject::constructor; 1431 1432MyObject::<span class="hljs-built_in">MyObject</span>(<span class="hljs-type">double</span> value) : <span class="hljs-built_in">value_</span>(value) { 1433} 1434 1435MyObject::~<span class="hljs-built_in">MyObject</span>() { 1436} 1437 1438<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::Init</span><span class="hljs-params">(Isolate* isolate)</span> </span>{ 1439 <span class="hljs-comment">// Prepare constructor template</span> 1440 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, New); 1441 tpl-><span class="hljs-built_in">SetClassName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 1442 tpl-><span class="hljs-built_in">InstanceTemplate</span>()-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); 1443 1444 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1445 constructor.<span class="hljs-built_in">Reset</span>(isolate, tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1446 1447 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, [](<span class="hljs-type">void</span>*) { 1448 constructor.<span class="hljs-built_in">Reset</span>(); 1449 }, <span class="hljs-literal">nullptr</span>); 1450} 1451 1452<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::New</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1453 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1454 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1455 1456 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">IsConstructCall</span>()) { 1457 <span class="hljs-comment">// Invoked as constructor: `new MyObject(...)`</span> 1458 <span class="hljs-type">double</span> value = args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsUndefined</span>() ? 1459 <span class="hljs-number">0</span> : args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">NumberValue</span>(context).<span class="hljs-built_in">FromMaybe</span>(<span class="hljs-number">0</span>); 1460 MyObject* obj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">MyObject</span>(value); 1461 obj-><span class="hljs-built_in">Wrap</span>(args.<span class="hljs-built_in">This</span>()); 1462 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(args.<span class="hljs-built_in">This</span>()); 1463 } <span class="hljs-keyword">else</span> { 1464 <span class="hljs-comment">// Invoked as plain function `MyObject(...)`, turn into construct call.</span> 1465 <span class="hljs-type">const</span> <span class="hljs-type">int</span> argc = <span class="hljs-number">1</span>; 1466 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1467 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1468 Local<Object> instance = 1469 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1470 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1471 } 1472} 1473 1474<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::NewInstance</span><span class="hljs-params">(<span class="hljs-type">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1475 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1476 1477 <span class="hljs-type">const</span> <span class="hljs-type">unsigned</span> argc = <span class="hljs-number">1</span>; 1478 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1479 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1480 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1481 Local<Object> instance = 1482 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1483 1484 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1485} 1486 1487} <span class="hljs-comment">// namespace demo</span></code> <button class="copy-button">copy</button></pre> 1488<p>Test it with:</p> 1489<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 1490<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 1491 1492<span class="hljs-keyword">const</span> obj1 = addon.<span class="hljs-title function_">createObject</span>(<span class="hljs-number">10</span>); 1493<span class="hljs-keyword">const</span> obj2 = addon.<span class="hljs-title function_">createObject</span>(<span class="hljs-number">20</span>); 1494<span class="hljs-keyword">const</span> result = addon.<span class="hljs-title function_">add</span>(obj1, obj2); 1495 1496<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(result); 1497<span class="hljs-comment">// Prints: 30</span></code> <button class="copy-button">copy</button></pre></section> 1498 <!-- API END --> 1499 </div> 1500 </div> 1501 </div> 1502</body> 1503</html> 1504