@@ -98,6 +98,140 @@ the `.node` suffix).
98
98
In the ` hello.cc ` example, then, the initialization function is ` Initialize `
99
99
and the addon module name is ` addon ` .
100
100
101
+ When building addons with ` node-gyp ` , using the macro ` NODE_GYP_MODULE_NAME ` as
102
+ the first parameter of ` NODE_MODULE() ` will ensure that the name of the final
103
+ binary will be passed to ` NODE_MODULE() ` .
104
+
105
+ ### Context-aware addons
106
+
107
+ There are environments in which Node.js addons may need to be loaded multiple
108
+ times in multiple contexts. For example, the [ Electron] [ ] runtime runs multiple
109
+ instances of Node.js in a single process. Each instance will have its own
110
+ ` require() ` cache, and thus each instance will need a native addon to behave
111
+ correctly when loaded via ` require() ` . From the addon's perspective, this means
112
+ that it must support multiple initializations.
113
+
114
+ A context-aware addon can be constructed by using the macro
115
+ ` NODE_MODULE_INITIALIZER ` , which expands to the name of a function which Node.js
116
+ will expect to find when it loads an addon. An addon can thus be initialized as
117
+ in the following example:
118
+
119
+ ``` cpp
120
+ using namespace v8 ;
121
+
122
+ extern "C" NODE_MODULE_EXPORT void
123
+ NODE_MODULE_INITIALIZER (Local<Object > exports,
124
+ Local<Value > module,
125
+ Local<Context > context) {
126
+ /* Perform addon initialization steps here. * /
127
+ }
128
+ ```
129
+
130
+ Another option is to use the macro `NODE_MODULE_INIT()`, which will also
131
+ construct a context-aware addon. Unlike `NODE_MODULE()`, which is used to
132
+ construct an addon around a given addon initializer function,
133
+ `NODE_MODULE_INIT()` serves as the declaration of such an initializer to be
134
+ followed by a function body.
135
+
136
+ The following three variables may be used inside the function body following an
137
+ invocation of `NODE_MODULE_INIT()`:
138
+ * `Local<Object> exports`,
139
+ * `Local<Value> module`, and
140
+ * `Local<Context> context`
141
+
142
+ The choice to build a context-aware addon carries with it the responsibility of
143
+ carefully managing global static data. Since the addon may be loaded multiple
144
+ times, potentially even from different threads, any global static data stored
145
+ in the addon must be properly protected, and must not contain any persistent
146
+ references to JavaScript objects. The reason for this is that JavaScript
147
+ objects are only valid in one context, and will likely cause a crash when
148
+ accessed from the wrong context or from a different thread than the one on which
149
+ they were created.
150
+
151
+ The context-aware addon can be structured to avoid global static data by
152
+ performing the following steps:
153
+ * defining a class which will hold per-addon-instance data. Such
154
+ a class should include a `v8::Persistent<v8::Object>` which will hold a weak
155
+ reference to the addon's `exports` object. The callback associated with the weak
156
+ reference will then destroy the instance of the class.
157
+ * constructing an instance of this class in the addon initializer such that the
158
+ `v8::Persistent<v8::Object>` is set to the `exports` object.
159
+ * storing the instance of the class in a `v8::External`, and
160
+ * passing the `v8::External` to all methods exposed to JavaScript by passing it
161
+ to the `v8::FunctionTemplate` constructor which creates the native-backed
162
+ JavaScript functions. The `v8::FunctionTemplate` constructor's third parameter
163
+ accepts the `v8::External`.
164
+
165
+ This will ensure that the per-addon-instance data reaches each binding that can
166
+ be called from JavaScript. The per-addon-instance data must also be passed into
167
+ any asynchronous callbacks the addon may create.
168
+
169
+ The following example illustrates the implementation of a context-aware addon:
170
+
171
+ ```cpp
172
+ #include <node.h>
173
+
174
+ using namespace v8;
175
+
176
+ class AddonData {
177
+ public:
178
+ AddonData(Isolate* isolate, Local<Object> exports):
179
+ call_count(0) {
180
+ // Link the existence of this object instance to the existence of exports.
181
+ exports_.Reset(isolate, exports);
182
+ exports_.SetWeak(this, DeleteMe, WeakCallbackType::kParameter);
183
+ }
184
+
185
+ ~AddonData() {
186
+ if (!exports_.IsEmpty()) {
187
+ // Reset the reference to avoid leaking data.
188
+ exports_.ClearWeak();
189
+ exports_.Reset();
190
+ }
191
+ }
192
+
193
+ // Per-addon data.
194
+ int call_count;
195
+
196
+ private:
197
+ // Method to call when "exports" is about to be garbage-collected.
198
+ static void DeleteMe(const WeakCallbackInfo<AddonData>& info) {
199
+ delete info.GetParameter();
200
+ }
201
+
202
+ // Weak handle to the "exports" object. An instance of this class will be
203
+ // destroyed along with the exports object to which it is weakly bound.
204
+ v8::Persistent<v8::Object> exports_;
205
+ };
206
+
207
+ static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
208
+ // Retrieve the per-addon-instance data.
209
+ AddonData* data =
210
+ reinterpret_cast<AddonData*>(info.Data().As<External>()->Value());
211
+ data->call_count++;
212
+ info.GetReturnValue().Set((double)data->call_count);
213
+ }
214
+
215
+ // Initialize this addon to be context-aware.
216
+ NODE_MODULE_INIT(/* exports, module, context */) {
217
+ Isolate* isolate = context->GetIsolate();
218
+
219
+ // Create a new instance of AddonData for this instance of the addon.
220
+ AddonData* data = new AddonData(isolate, exports);
221
+ // Wrap the data in a v8::External so we can pass it to the method we expose.
222
+ Local<External> external = External::New(isolate, data);
223
+
224
+ // Expose the method "Method" to JavaScript, and make sure it receives the
225
+ // per-addon-instance data we created above by passing `external` as the
226
+ // third parameter to the FunctionTemplate constructor.
227
+ exports->Set(context,
228
+ String::NewFromUtf8(isolate, "method", NewStringType::kNormal)
229
+ .ToLocalChecked(),
230
+ FunctionTemplate::New(isolate, Method, external)
231
+ ->GetFunction(context).ToLocalChecked()).FromJust();
232
+ }
233
+ ```
234
+
101
235
### Building
102
236
103
237
Once the source code has been written, it must be compiled into the binary
@@ -1162,6 +1296,7 @@ Test in JavaScript by running:
1162
1296
require('./build/Release/addon');
1163
1297
```
1164
1298
1299
+ [ Electron]: https:// electronjs.org/
1165
1300
[Embedder' s Guide]: https://github.com/v8/v8/wiki/Embedder' s%20Guide
1166
1301
[Linking to Node.js' own dependencies]: #addons_linking_to_node_js_own_dependencies
1167
1302
[Native Abstractions for Node.js]: https://github.com/nodejs/nan
0 commit comments