# Add-on Structure

Class `Napi::Addon<T>` inherits from class [`Napi::InstanceWrap<T>`][].

Creating add-ons that work correctly when loaded multiple times from the same
source package into multiple Node.js threads and/or multiple times into the same
Node.js thread requires that all global data they hold be associated with the
environment in which they run. It is not safe to store global data in static
variables because doing so does not take into account the fact that an add-on
may be loaded into multiple threads nor that an add-on may be loaded multiple
times into a single thread.

The `Napi::Addon<T>` class can be used to define an entire add-on. Instances of
`Napi::Addon<T>` subclasses become instances of the add-on, stored safely by
Node.js on its various threads and into its various contexts. Thus, any data
stored in the instance variables of a `Napi::Addon<T>` subclass instance are
stored safely by Node.js. Functions exposed to JavaScript using
`Napi::Addon<T>::InstanceMethod` and/or `Napi::Addon<T>::DefineAddon` are
instance methods of the `Napi::Addon` subclass and thus have access to data
stored inside the instance.

`Napi::Addon<T>::DefineProperties` may be used to attach `Napi::Addon<T>`
subclass instance methods to objects other than the one that will be returned to
Node.js as the add-on instance.

The `Napi::Addon<T>` class can be used together with the `NODE_API_ADDON()` and
`NODE_API_NAMED_ADDON()` macros to define add-ons.

## Example

```cpp
#include <napi.h>

class ExampleAddon : public Napi::Addon<ExampleAddon> {
 public:
  ExampleAddon(Napi::Env env, Napi::Object exports) {
    // In the constructor we declare the functions the add-on makes available
    // to JavaScript.
    DefineAddon(exports, {
      InstanceMethod("increment", &ExampleAddon::Increment),

      // We can also attach plain objects to `exports`, and instance methods as
      // properties of those sub-objects.
      InstanceValue("subObject", DefineProperties(Napi::Object::New(env), {
        InstanceMethod("decrement", &ExampleAddon::Decrement)
      }), napi_enumerable)
    });
  }
 private:

  // This method has access to the data stored in the environment because it is
  // an instance method of `ExampleAddon` and because it was listed among the
  // property descriptors passed to `DefineAddon()` in the constructor.
  Napi::Value Increment(const Napi::CallbackInfo& info) {
    return Napi::Number::New(info.Env(), ++value);
  }

  // This method has access to the data stored in the environment because it is
  // an instance method of `ExampleAddon` and because it was exposed to
  // JavaScript by calling `DefineProperties()` with the object onto which it is
  // attached.
  Napi::Value Decrement(const Napi::CallbackInfo& info) {
    return Napi::Number::New(info.Env(), --value);
  }

  // Data stored in these variables is unique to each instance of the add-on.
  uint32_t value = 42;
};

// The macro announces that instances of the class `ExampleAddon` will be
// created for each instance of the add-on that must be loaded into Node.js.
NODE_API_ADDON(ExampleAddon)
```

The above code can be used from JavaScript as follows:

```js
'use strict'

const exampleAddon = require('bindings')('example_addon');
console.log(exampleAddon.increment()); // prints 43
console.log(exampleAddon.increment()); // prints 44
console.log(exampleAddon.subObject.decrement()); // prints 43
```

When Node.js loads an instance of the add-on, a new instance of the class is
created. Its constructor receives the environment `Napi::Env env` and the
exports object `Napi::Object exports`. It can then use the method `DefineAddon`
to either attach methods, accessors, and/or values to the `exports` object or to
create its own `exports` object and attach methods, accessors, and/or values to
it.

**Note:** `Napi::Addon<T>` uses `Napi::Env::SetInstanceData()` internally. This
means that the add-on should only use `Napi::Env::GetInstanceData` explicitly to
retrieve the instance of the `Napi::Addon<T>` class. Variables whose scope would
otherwise be global should be stored as instance variables in the
`Napi::Addon<T>` class.

Functions created with `Napi::Function::New()`, accessors created with
`PropertyDescriptor::Accessor()`, and values can also be attached. If their
implementation requires the `ExampleAddon` instance, it can be retrieved from
the `Napi::Env env` with `GetInstanceData()`:

```cpp
void ExampleBinding(const Napi::CallbackInfo& info) {
  ExampleAddon* addon = info.Env().GetInstanceData<ExampleAddon>();
}
```

## Methods

### Constructor

Creates a new instance of the add-on.

```cpp
Napi::Addon(Napi::Env env, Napi::Object exports);
```

- `[in] env`: The environment into which the add-on is being loaded.
- `[in] exports`: The exports object received from JavaScript.

Typically, the constructor calls `DefineAddon()` to attach methods, accessors,
and/or values to `exports`. The constructor may also create a new object and
pass it to `DefineAddon()` as its first parameter if it wishes to replace the
`exports` object as provided by Node.js.

### DefineAddon

Defines an add-on instance with functions, accessors, and/or values.

```cpp
template <typename T>
void Napi::Addon<T>::DefineAddon(Napi::Object exports,
                   const std::initializer_list<PropertyDescriptor>& properties);
```

* `[in] exports`: The object to return to Node.js as an instance of the add-on.
* `[in] properties`: Initializer list of add-on property descriptors of the
methods, property accessors, and values that define the add-on. They will be
set on `exports`.
See: [`Class property and descriptor`](class_property_descriptor.md).

### DefineProperties

Defines function, accessor, and/or value properties on an object using add-on
instance methods.

```cpp
template <typename T>
Napi::Object
Napi::Addon<T>::DefineProperties(Napi::Object object,
                   const std::initializer_list<PropertyDescriptor>& properties);
```

* `[in] object`: The object that will receive the new properties.
* `[in] properties`: Initializer list of property descriptors of the methods,
property accessors, and values to attach to `object`.
See: [`Class property and descriptor`](class_property_descriptor.md).

Returns `object`.

[`Napi::InstanceWrap<T>`]: ./instance_wrap.md
