lokesh / color-thief

Grab the color palette from an image using just Javascript. Works in the browser and in Node.
https://lokeshdhakar.com/projects/color-thief/
MIT License
12.34k stars 1.31k forks source link

node-gyp error coming from node-canvas #206

Closed talentlessguy closed 1 year ago

talentlessguy commented 3 years ago

system info

node: v15.11.0 pnpm: 5.18.3 npm: 7.6.0

When trying to install color-thief with pnpm, I get this:

➜ pnpm i color-thief
Packages: +51
+++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 159, reused 159, downloaded 0, added 0, done
node_modules/.pnpm/canvas@2.5.0/node_modules/canvas: Running install script, failed in 7.6s
.../canvas@2.5.0/node_modules/canvas install$ node-pre-gyp install --fallback-to-build
│ node-pre-gyp info it worked if it ends with ok
│ node-pre-gyp info using node-pre-gyp@0.11.0
│ node-pre-gyp info using node@15.11.0 | linux | x64
│ node-pre-gyp WARN Using request for node-pre-gyp https download 
│ node-pre-gyp info check checked for "/home/v1rtl/Coding/badge.crypto/node_modules/.pnpm/canvas@2
│ node-pre-gyp http GET https://github.com/node-gfx/node-canvas-prebuilt/releases/download/v2.5.0/
│ node-pre-gyp http 404 https://github.com/node-gfx/node-canvas-prebuilt/releases/download/v2.5.0/
│ node-pre-gyp WARN Tried to download(404): https://github.com/node-gfx/node-canvas-prebuilt/relea
│ node-pre-gyp WARN Pre-built binaries not found for canvas@2.5.0 and node@15.11.0 (node-v88 ABI, 
│ node-pre-gyp http 404 status code downloading tarball https://github.com/node-gfx/node-canvas-pr
│ gyp info it worked if it ends with ok
│ gyp info using node-gyp@7.1.2
│ gyp info using node@15.11.0 | linux | x64
│ gyp info ok 
│ gyp info it worked if it ends with ok
│ gyp info using node-gyp@7.1.2
│ gyp info using node@15.11.0 | linux | x64
│ gyp info find Python using Python version 3.9.2 found at "/usr/bin/python3"
│ gyp info spawn /usr/bin/python3
│ gyp info spawn args [
│ gyp info spawn args   '/home/v1rtl/.pnpm-store/pnpm-global/4/node_modules/.pnpm/pnpm@5.18.3/node
│ gyp info spawn args   'binding.gyp',
│ gyp info spawn args   '-f',
│ gyp info spawn args   'make',
│ gyp info spawn args   '-I',
│ gyp info spawn args   '/home/v1rtl/Coding/badge.crypto/node_modules/.pnpm/canvas@2.5.0/node_modu
│ gyp info spawn args   '-I',
│ gyp info spawn args   '/home/v1rtl/.pnpm-store/pnpm-global/4/node_modules/.pnpm/pnpm@5.18.3/node
│ gyp info spawn args   '-I',
│ gyp info spawn args   '/home/v1rtl/.cache/node-gyp/15.11.0/include/node/common.gypi',
│ gyp info spawn args   '-Dlibrary=shared_library',
│ gyp info spawn args   '-Dvisibility=default',
│ gyp info spawn args   '-Dnode_root_dir=/home/v1rtl/.cache/node-gyp/15.11.0',
│ gyp info spawn args   '-Dnode_gyp_dir=/home/v1rtl/.pnpm-store/pnpm-global/4/node_modules/.pnpm/p
│ gyp info spawn args   '-Dnode_lib_file=/home/v1rtl/.cache/node-gyp/15.11.0/<(target_arch)/node.l
│ gyp info spawn args   '-Dmodule_root_dir=/home/v1rtl/Coding/badge.crypto/node_modules/.pnpm/canv
│ gyp info spawn args   '-Dnode_engine=v8',
│ gyp info spawn args   '--depth=.',
│ gyp info spawn args   '--no-parallel',
│ gyp info spawn args   '--generator-output',
│ gyp info spawn args   'build',
│ gyp info spawn args   '-Goutput_dir=.'
│ gyp info spawn args ]
│ gyp info ok 
│ gyp info it worked if it ends with ok
│ gyp info using node-gyp@7.1.2
│ gyp info using node@15.11.0 | linux | x64
│ gyp info spawn make
│ gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
│ make: Entering directory '/home/v1rtl/Coding/badge.crypto/node_modules/.pnpm/canvas@2.5.0/node_m
│   SOLINK_MODULE(target) Release/obj.target/canvas-postbuild.node
│   COPY Release/canvas-postbuild.node
│   CXX(target) Release/obj.target/canvas/src/backend/Backend.o
│   CXX(target) Release/obj.target/canvas/src/backend/ImageBackend.o
│ ../src/backend/ImageBackend.cc: In static member function ‘static void ImageBackend::Initialize(
│ ../src/backend/ImageBackend.cc:70:56: warning: ignoring return value of ‘v8::Maybe<bool> v8::Obj
│    70 |               ctor->GetFunction(v8ctx).ToLocalChecked());
│       |                                                        ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/backend/ImageBackend.h:3,
│                  from ../src/backend/ImageBackend.cc:1:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3716:37: note: declared here
│  3716 |   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
│       |                                     ^~~
│   CXX(target) Release/obj.target/canvas/src/backend/PdfBackend.o
│ ../src/backend/PdfBackend.cc: In static member function ‘static void PdfBackend::Initialize(v8::
│ ../src/backend/PdfBackend.cc:49:56: warning: ignoring return value of ‘v8::Maybe<bool> v8::Objec
│    49 |               ctor->GetFunction(v8ctx).ToLocalChecked());
│       |                                                        ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/backend/PdfBackend.h:3,
│                  from ../src/backend/PdfBackend.cc:1:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3716:37: note: declared here
│  3716 |   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
│       |                                     ^~~
│   CXX(target) Release/obj.target/canvas/src/backend/SvgBackend.o
│ ../src/backend/SvgBackend.cc: In static member function ‘static void SvgBackend::Initialize(v8::
│ ../src/backend/SvgBackend.cc:51:56: warning: ignoring return value of ‘v8::Maybe<bool> v8::Objec
│    51 |               ctor->GetFunction(v8ctx).ToLocalChecked());
│       |                                                        ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/backend/SvgBackend.h:3,
│                  from ../src/backend/SvgBackend.cc:1:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3716:37: note: declared here
│  3716 |   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
│       |                                     ^~~
│   CXX(target) Release/obj.target/canvas/src/bmp/BMPParser.o
│   CXX(target) Release/obj.target/canvas/src/Backends.o
│ ../src/Backends.cc: In static member function ‘static void Backends::Initialize(v8::Local<v8::Ob
│ ../src/Backends.cc:18:72: warning: ignoring return value of ‘v8::Maybe<bool> v8::Object::Set(v8:
│    18 |   target->Set(v8ctx, Nan::New<String>("Backends").ToLocalChecked(), obj);
│       |                                                                        ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/Backends.h:3,
│                  from ../src/Backends.cc:1:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3716:37: note: declared here
│  3716 |   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
│       |                                     ^~~
│   CXX(target) Release/obj.target/canvas/src/Canvas.o
│ ../src/Canvas.cc: In function ‘void setPdfMetaStr(cairo_surface_t*, v8::Local<v8::Object>, cairo
│ ../src/Canvas.cc:327:25: error: no matching function for call to ‘v8::Object::Get(v8::Local<v8::
│   327 |   if (opts->Get(propName)->IsString()) {
│       |                         ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/Canvas.h:5,
│                  from ../src/Canvas.cc:3:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note: candidate: ‘v8::MaybeLocal<
│  3763 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note:   candidate expects 2 argum
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note: candidate: ‘v8::MaybeLocal<
│  3766 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note:   candidate expects 2 argum
│ ../src/Canvas.cc:328:34: error: no matching function for call to ‘v8::Object::Get(v8::Local<v8::
│   328 |     auto val = opts->Get(propName);
│       |                                  ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/Canvas.h:5,
│                  from ../src/Canvas.cc:3:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note: candidate: ‘v8::MaybeLocal<
│  3763 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note:   candidate expects 2 argum
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note: candidate: ‘v8::MaybeLocal<
│  3766 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note:   candidate expects 2 argum
│ ../src/Canvas.cc: In function ‘void setPdfMetaDate(cairo_surface_t*, v8::Local<v8::Object>, cair
│ ../src/Canvas.cc:337:25: error: no matching function for call to ‘v8::Object::Get(v8::Local<v8::
│   337 |   if (opts->Get(propName)->IsDate()) {
│       |                         ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/Canvas.h:5,
│                  from ../src/Canvas.cc:3:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note: candidate: ‘v8::MaybeLocal<
│  3763 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note:   candidate expects 2 argum
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note: candidate: ‘v8::MaybeLocal<
│  3766 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note:   candidate expects 2 argum
│ ../src/Canvas.cc:338:34: error: no matching function for call to ‘v8::Object::Get(v8::Local<v8::
│   338 |     auto val = opts->Get(propName).As<Date>();
│       |                                  ^
│ In file included from /home/v1rtl/.cache/node-gyp/15.11.0/include/node/node.h:63,
│                  from ../../../../nan@2.14.2/node_modules/nan/nan.h:56,
│                  from ../src/backend/Backend.h:6,
│                  from ../src/Canvas.h:5,
│                  from ../src/Canvas.cc:3:
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note: candidate: ‘v8::MaybeLocal<
│  3763 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3763:43: note:   candidate expects 2 argum
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note: candidate: ‘v8::MaybeLocal<
│  3766 |   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
│       |                                           ^~~
│ /home/v1rtl/.cache/node-gyp/15.11.0/include/node/v8.h:3766:43: note:   candidate expects 2 argum
│ ../src/Canvas.cc:338:43: error: expected primary-expression before ‘>’ token
│   338 |     auto val = opts->Get(propName).As<Date>();
│       |                                           ^
│ ../src/Canvas.cc:338:45: error: expected primary-expression before ‘)’ token
│   338 |     auto val = opts->Get(propName).As<Date>();
│       |                                             ^
│ ../src/Canvas.cc: In static member function ‘static Nan::NAN_METHOD_RETURN_TYPE Canvas::ToBuffer
│ ../src/Canvas.cc:475:61: warning: cast between incompatible function types from ‘void (*)(uv_wor
│   475 |     uv_queue_work(uv_default_loop(), req, ToPngBufferAsync, (uv_after_work_cb)ToBufferAs
│       |                                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
│ ../src/Canvas.cc:516:62: warning: cast between incompatible function types from ‘void (*)(uv_wor
│   516 |     uv_queue_work(uv_default_loop(), req, ToJpegBufferAsync, (uv_after_work_cb)ToBufferA
│       |                                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~
│ make: *** [canvas.target.mk:158: Release/obj.target/canvas/src/Canvas.o] Error 1
│ make: Leaving directory '/home/v1rtl/Coding/badge.crypto/node_modules/.pnpm/canvas@2.5.0/node_mo
│ gyp ERR! build error 
│ gyp ERR! stack Error: `make` failed with exit code: 2
│ gyp ERR! stack     at ChildProcess.onExit (/home/v1rtl/.pnpm-store/pnpm-global/4/node_modules/.p
│ gyp ERR! stack     at ChildProcess.emit (node:events:378:20)
│ gyp ERR! stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
│ gyp ERR! System Linux 5.10.19-1-MANJARO
│ gyp ERR! command "/home/v1rtl/n/bin/node" "/home/v1rtl/.pnpm-store/pnpm-global/4/node_modules/.p
│ gyp ERR! cwd /home/v1rtl/Coding/badge.crypto/node_modules/.pnpm/canvas@2.5.0/node_modules/canvas
│ gyp ERR! node -v v15.11.0
│ gyp ERR! node-gyp -v v7.1.2
│ gyp ERR! not ok 
│ node-pre-gyp ERR! build error 
│ node-pre-gyp ERR! stack Error: Failed to execute '/home/v1rtl/n/bin/node /home/v1rtl/.pnpm-store
│ node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/home/v1rtl/Coding/badge.crypto/node_mo
│ node-pre-gyp ERR! stack     at ChildProcess.emit (node:events:378:20)
│ node-pre-gyp ERR! stack     at maybeClose (node:internal/child_process:1067:16)
│ node-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:
│ node-pre-gyp ERR! System Linux 5.10.19-1-MANJARO
│ node-pre-gyp ERR! command "/home/v1rtl/n/bin/node" "/home/v1rtl/Coding/badge.crypto/node_modules
│ node-pre-gyp ERR! cwd /home/v1rtl/Coding/badge.crypto/node_modules/.pnpm/canvas@2.5.0/node_modul
│ node-pre-gyp ERR! node -v v15.11.0
│ node-pre-gyp ERR! node-pre-gyp -v v0.11.0
│ node-pre-gyp ERR! not ok 
│ Failed to execute '/home/v1rtl/n/bin/node /home/v1rtl/.pnpm-store/pnpm-global/4/node_modules/.pn
└─ Failed in 7.6s
 ERROR  Command failed with exit code 1.
RudeySH commented 2 years ago

202 is related.

node-canvas is not actually a dependency of color-thief. The actual dependency that's causing this is lokesh/quantize which is referenced in the package.json like this:

    "dependencies": {
        "get-pixels": "^3.3.2",
        "quantize": "github:lokesh/quantize"
    }

Since npm 7.0.9, when referencing dependencies like this (github:), npm will try to install the devDependencies of the dependencies of lokesh/quantize. This issue is tracked here: https://github.com/npm/cli/issues/2784.

Because lokesh/quantize has a devDependency on microbundle@0.11.0, and this version of microbundle uses node-gyp, and these packages require additional development tools to be installed, we run into issues when trying to install color-thief.

There are numerous solutions/workarounds:

  1. Wait for npm to fix https://github.com/npm/cli/issues/2784
  2. Have @lokesh turn lokesh/quantize into an actual npm package, and replace the github:-style dependency in color-thief
  3. Update microbundle to a newer version that doesn't require node-gyp (see my PR, https://github.com/lokesh/quantize/pull/2)
  4. Downgrade to color-thief@2.2.0

Until npm or lokesh makes a move, your only option is number 4.

kamilmielnik commented 2 years ago

Until npm or lokesh makes a move, your only option is number 4.

or

  1. Use older npm + node. I tried a few different versions and finally npm@6.14.4 + node@12.18.0 worked fine for me with color-thief@2.2.5.
RudeySH commented 2 years ago

Ah of course, that's also an option. npm 7.0.8 or lower should work fine.

pioug commented 2 years ago

The recent versions of npm support overrides to replace a version of dependency.

Using the quantize fork of @RudeySH works for me. Tested node@18.0.0 + npm@8.9.0.

{
  "dependencies": {
    "colorthief": "^2.3.2"
  },
  "overrides": {
    "quantize": "github:RudeySH/quantize"
  }
}

UPDATE: I created a monorepo with colorthief including some (abandoned) dependencies that needed an update too. It's not super classy to share it here but we are losing so much time collectively trying to fix this. Please head over to https://github.com/pioug/colorsuite. If anyone is interested in keeping the project/repository alive, ping me there, I'll add you as a maintainer.

npm install colorthief@npm:@pioug/colorthief
svvimming commented 1 year ago

thanks @pioug works great! 👍

lokesh commented 1 year ago

Have @lokesh turn lokesh/quantize into an actual npm package, and replace the github:-style dependency in color-thief

Finally... done. The package on npmjs.com: https://www.npmjs.com/package/@lokesh.dhakar/quantize

The latest release of color-thief updates the quantize dep reference in package.json: https://github.com/lokesh/color-thief/releases/tag/v2.4.0