You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've been experimenting with worker threads in node.js recently and noticed that the canvas module does not appear to be context-aware. In other words, the module will load/instantiate once, but as soon as another thread attempts to require canvas for it's own use, the following error is thrown:
Error: Module did not self-register.
at Object.Module._extensions..node (internal/modules/cjs/loader.js:840:18)
at Module.load (internal/modules/cjs/loader.js:666:32)
at tryModuleLoad (internal/modules/cjs/loader.js:606:12)
at Function.Module._load (internal/modules/cjs/loader.js:598:3)
at Module.require (internal/modules/cjs/loader.js:705:19)
at require (internal/modules/cjs/helpers.js:14:16)
at Object.<anonymous> (~/node_modules/canvas/lib/bindings.js:3:18)
at Module._compile (internal/modules/cjs/loader.js:799:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:810:10)
at Module.load (internal/modules/cjs/loader.js:666:32)
Steps to Reproduce
In main thread...
const{Worker}=require('worker_threads');varworker1=newWorker('./child-thread.js');varworker2=newWorker('./child-thread.js');// etc.
In child-thread.js...
varCanvas=require('canvas');varcanvas=Canvas.createCanvas(200,200);varctx=canvas.getContext('2d');// etc.
Reacted by Gao Yingjian, jgoralcz, LeaPhant, Vitalii Dub, Randall, Sean, Ruiwei Qi, David Kartnaller, GC, Sergej Sintschilin and 68 more
Reacted by Alain Perkaz, Mathieu Benard, Fawaz Alharbi, Maverickk, Harold Iedema, Peyton Creery, Loneless, Benjamin MICHEL, silverwind, Zerry Hogan and 1 more
I'm having the same issue. I'd love to be able to use node-canvas in multiple worker threads to improve performance. Anyone want to tackle this? Seems like it should be straightforward to solve:
Looks like I'll have a chance to maybe take a stab at this in a week while I'm on leave. No promises. Has anyone else had a chance to take a look at it? If so, I'd be great to avoid hours of re-discovery.
Reacted by Cosmiiko and Alain Perkaz
Reacted by Anna, voehl, Rhuan, Max Reisner, Cosmiiko and Alain Perkaz
Callback that accesses per NodeJS instance addon data
voidencode(const FunctionCallbackInfo<Value>& info) {
// Retrieve the per-addon-instance data
AddonData* data = reinterpret_cast<AddonData*>(info.Data().As<External>()->Value());
// encode YUV420 from buf
data->encode();
// construct h264 bitstream from bitstream info
data->parseBitstreamInfo();
data->bsiab = node::Buffer::New(info.GetIsolate(), (char*) data->bsi.data(), (size_t) data->bsiSize, AddonData::abDeleteCb, (void*) &data->bsiab);
info.GetReturnValue().Set(data->bsiab.ToLocalChecked());
}
Per NodeJS instance module initializer (another method of initialization can be used too but this one was used in another addon that works with worker_threads and I'm total C++ noob)
extern"C"NODE_MODULE_EXPORTvoidNODE_MODULE_INITIALIZER(Local<Object> exports, Local<Value> module, Local<Context> context) {
Isolate* isolate = context->GetIsolate();
// Create a new instance of `AddonData` for this instance of the addon and// tie its life cycle to that of the Node.js environment
AddonData* data = newAddonData(isolate);
// create encoder instance
data->createEncoder();
// Wrap the data in a `v8::External` so we can pass it to the method we expose
Local<External> external = External::New(isolate, data);
// ... omitted
exports->Set(
context,
String::NewFromUtf8(isolate, "encode", NewStringType::kNormal).ToLocalChecked(),
FunctionTemplate::New(isolate, encode, external)->GetFunction(context).ToLocalChecked()
).FromJust();
}
I tried getting this to work with no success... If anyone who's more c++ oriented than me (and I'm not) would want some help fixing this, I'd be happy to help!
I hope i'm not leading anyone astray, as I have no clue how the node API bindings work with creating a context-aware module; but I found a module called 'node-lzo' that has made changes to adapt their library, that I don't see present here.
Reacted by Patryk Kotarski, Markos Girgis, AlexMoutonNoble, Vladimir Dumitraskovic, Marcelo Lv Cabral, hinst, Harrison Milbradt, Isaac, caly-quilt, Juniel Cruz and 7 more
qbq-ber-alexander-fritsch commented on Jul 4, 2024
The proposed workaround is NOT good for all use cases, I need it as a Worker, because my application uses SharedArrayBuffer to communicate to the Worker, there are other issues, that I would have to rewrite several portions of the app. The ideal was really to have Canvas support in Worker, just like the Browser has.
I'm more than halfway through redoing the font stack and prebuilds, and this is on my radar. I don't think we will have any more global/static data after that. It will definitely be done, it just depends on how much free time I have.
Reacted by Sam Schurter, Younes, Ramsay, 弘树, Max Stevens, Marcelo Lv Cabral, Christian Hartinger and Vitalii Dub
Yes, I finished all the hard stuff for v4 (#2476) and it will be out soon! I just tried 4 canvases in parallel via worker threads. I had to tweak a few things, but it worked, with different fonts and SVG rendering in parallel:
Development is happening on the next branch. I have to review and test more, then figure out the new way to distribute binaries (#2595) but we're very close.
Reacted by Younes, Randall, Zirafnik, David Šabata, Ramsay, Patryk L. and 弘树
Activity
LinusU commentedon Apr 1, 2019
PRs welcome 👍
jgoralcz commentedon Jun 1, 2019
This would be an incredible addition to node-canvas. Not sure where to fully dive in and modify the code though 🤔
ruiwei commentedon Oct 2, 2019
anshul-kai commentedon Oct 3, 2019
Nope. Need to fork processes and can't use worker threads.
siddarthareddyt commentedon Nov 6, 2019
#1409 doesn't seem to fix this issue. Any plans to provide support for
worker_threads?DePasqualeOrg commentedon Jan 31, 2020
I'm having the same issue. I'd love to be able to use node-canvas in multiple worker threads to improve performance. Anyone want to tackle this? Seems like it should be straightforward to solve:
https://github.com/nodejs/node/blob/master/doc/api/addons.md#context-aware-addons
mistval commentedon Feb 15, 2020
lateiskate commentedon Mar 18, 2020
anna-rmrf commentedon Jul 4, 2020
mac-g commentedon Jul 4, 2020
Looks like I'll have a chance to maybe take a stab at this in a week while I'm on leave. No promises. Has anyone else had a chance to take a look at it? If so, I'd be great to avoid hours of re-discovery.
lostrepo commentedon Jul 5, 2020
Maybe this will help.
I'm total noob in C++
But I use something like that to use h264 encoder in worker_threads
Per NodeJS instance addon data
Callback that accesses per NodeJS instance addon data
Per NodeJS instance module initializer (another method of initialization can be used too but this one was used in another addon that works with worker_threads and I'm total C++ noob)
maxreisner commentedon Jul 23, 2020
I tried getting this to work with no success... If anyone who's more c++ oriented than me (and I'm not) would want some help fixing this, I'd be happy to help!
Mjtlittle commentedon Sep 7, 2020
I hope i'm not leading anyone astray, as I have no clue how the node API bindings work with creating a context-aware module; but I found a module called 'node-lzo' that has made changes to adapt their library, that I don't see present here.
schroffl/node-lzo#11
specifically this replacement...
enricodeleo commentedon Sep 20, 2020
30 remaining items
BowgartField commentedon Dec 15, 2023
any updates ?
qbq-ber-alexander-fritsch commentedon Jul 4, 2024
Also just ran into the issue of
Module did not self-register, even in3.0.0-rc2.Would love to see this happen, would really make my time a lot easier ;D
deflexable commentedon Sep 20, 2024
any updates on this?
Zirafnik commentedon Oct 12, 2024
As @anshul-kai pointed out above, the current workaround is to use Node.js
child_processesinstead ofworker_threads.From what I've tested, that way works fine.
lvcabral commentedon Feb 20, 2025
The proposed
workaroundis NOT good for all use cases, I need it as a Worker, because my application uses SharedArrayBuffer to communicate to the Worker, there are other issues, that I would have to rewrite several portions of the app. The ideal was really to have Canvas support in Worker, just like the Browser has.lvcabral commentedon Jan 9, 2026
Bump! One year later, any chance this will ever be implemented?
chearon commentedon Jan 9, 2026
I'm more than halfway through redoing the font stack and prebuilds, and this is on my radar. I don't think we will have any more global/static data after that. It will definitely be done, it just depends on how much free time I have.
lvcabral commentedon Jan 10, 2026
@chearon thanks for the feedback!
lvcabral commentedon Jun 26, 2026
@chearon just a quick check, any update for us?
chearon commentedon Jun 27, 2026
Yes, I finished all the hard stuff for v4 (#2476) and it will be out soon! I just tried 4 canvases in parallel via worker threads. I had to tweak a few things, but it worked, with different fonts and SVG rendering in parallel:
Development is happening on the
nextbranch. I have to review and test more, then figure out the new way to distribute binaries (#2595) but we're very close.lvcabral commentedon Jun 27, 2026
@chearon I really appreciate the effort! This will unlock the CLI version of my open source Roku simulator to also support Task threads!