mmomtchev / magickwand.js

Full native ImageMagick-7 bindings for Node.js native & WASM - showcase for SWIG Node-API
ISC License
49 stars 6 forks source link

Struggling to install and use this library #224

Closed Francesco-Lanciana closed 1 week ago

Francesco-Lanciana commented 1 week ago

I've attempted several ways to get this library to run but I can't even get a basic example working. I'm probably just not understanding a core concept and doing something silly but I'd really appreciate your help in resolving this.

My end goal is to execute the WASM binary in a Node.js process (on a cloud function) to convert HEIC images to JPG.

I've tried the following with the latest Node.js lts version (20.17.0) and the latest version (22.8.0). I am 2016 MacBook Pro (Intel Core i7) running OS 12.3.1.

Attempt 1: Following the instructions in the README

Step 1: Create a fresh directory and run npm install magickwand.js Step 2: Add "type": "module" to the package.json Step 3: Create an index.js file with the following code

import ImageMagick from 'magickwand.js';
const { Magick, MagickCore } = await ImageMagick;

Step 4: Run node index.js

Result: This gave me the following error: The requested module 'magickwand.js' does not provide an export named 'default'

Attempt 2: Grabbing the WASM files from node_modules

Step 1: Create a fresh directory and run npm install magickwand.js Step 2: Add "type": "module" to the package.json Step 3: Copy magickwand.js and magickwand.wasm from "node_modules/magickwand.js/lib/binding/emscripten-wasm32" into the root of the directory Step 4: Create an index.js file with the following code

import ImageMagick from './magickwand.js';
import { fileURLToPath } from 'url';
import * as path from 'path';

const Magick = await ImageMagick;
const wizard = path.join(fileURLToPath(import.meta.url), 'test.HEIC');
let im = new Magick.Image(wizard);

Step 5: Run node index.js

Result: This gave me the following error: TypeError: Magick.Image is not a constructor

Request

If possible I would love help with the following:

Also I'm pretty new to WASM so if what I'm trying to do makes no sense please let me know. My assumption is that a WASM binary should run anywhere (including in a cloud function if it's small enough) without the need for a complex build step, e.g. with Sharp I would need to create a docker container with the correct dependencies.

Thanks in advance for the help.

mmomtchev commented 1 week ago

The WASM version does not have Node.js support as Node.js has its own native build which is much better in every way.

Additionally, adding Node.js support to the WASM loader confuses the bundlers and requires special configuration when building a web application.

You don't have to manually copy anything. You just have to import the module from its default location.

You can eventually build your own WASM binaries that support Node.js by modifying meson.build and removing this line: 'environments': ['web', 'webview', 'worker']

Francesco-Lanciana commented 1 week ago

Thanks for the response. Good to know that the WASM version does not have Node.js support.

So just a few follow up questions:

  1. How do I actually get this to work in a node program? (My original question posted the steps I followed when trying and the error I received when importing the module from it's default location)
  2. To produce an optimised build with npm do I just have to do something like npm install imagemagick.js --disable-tiff --...? Will this rebuild imagemagick.js on my local device or is it pulling a prebuilt version? I'm mainly wondering if I have a cloud function with this dependency do I have to do anything to make it build correctly in a cloud environment
  3. In what ways is the native build better?
mmomtchev commented 1 week ago

What happens if you simply follow the instruction in Installation and Importing on the homepage?

Francesco-Lanciana commented 1 week ago

@mmomtchev that's what I'm trying to do but it doesn't work. The exact steps I take are as follows:

  1. Create a new folder for the test project
  2. Run npm install magickwand.js inside this folder
  3. Create an index.js file
  4. Copy the following code into index.js
    import ImageMagick from 'magickwand.js';
    // ImageMagick will be either a native library
    // (if called from a Node.js application)
    // or a WASM bundle (when bundled by a web bundler)
    const { Magick, MagickCore } = await ImageMagick;
  5. Run node index.js

That gives me the error: Cannot use import statement outside a module

  1. I added "type": "module", to the package.json to resolve the above error
  2. Run node index.js

Which now gives me the error The requested module 'magickwand.js' does not provide an export named 'default'.

I might just be missing something really obvious regarding how I'm supposed to be running node whilst using import instead of require.

mmomtchev commented 1 week ago

You installed magickwand.js 1.x and you used the installation/usage instructions for the latest 2.x beta.

Check https://www.npmjs.com/package/magickwand.js - both versions have their own installation/usage instructions.

2.x features an automatic resolver that selects either WASM or Node.js depending on the environment.

Francesco-Lanciana commented 5 days ago

Ahh right, missed the version, thanks for the help.

One more related question though. I had to install libx11 and libXext using brew in order to run for the code in my previous comment. I've read for operations where libx11 is not needed (e.g. conversions) it's possible to bypass installing it. I would like to run this program on a cloud function without the need to install libx11 and libXext. Is this possible? If so I'd really appreciate if you could show me how I achieve that.

mmomtchev commented 5 days ago

The next release should come with prebuilt binaries built without libX11 and libXext. Currently, you have to rebuild from source.