sharp icon indicating copy to clipboard operation
sharp copied to clipboard

Sharp is not working with "Bun build --compile"

Open buzzy opened this issue 1 year ago • 12 comments

When compiling a binary using "Bun build --compile", it seems that the resulting binary does not contain the "binary" of Sharp. It still tries to load it from ./node_modules. If I copy the node_modules directory together with the resulting binary from "Bun build", it runs without issues. I am not sure if this is an issue with "Bun build" or with Sharp, but other node-related binaries from node_modules are working for me.

buzzy avatar Nov 23 '24 20:11 buzzy

It's very unlikely that bun build --compile will work with sharp as it attempts to create a single executable, however sharp and libvips are provided as shared dynamic libraries.

lovell avatar Nov 23 '24 22:11 lovell

It's very unlikely that bun build --compile will work with sharp as it attempts to create a single executable, however sharp and libvips are provided as shared dynamic libraries.

Well, so does sqlite, but that works with Bun. I am not talking about the built in version, but the node module. Bun embeds the lib into the binary on --compile

buzzy avatar Nov 24 '24 00:11 buzzy

Bun provides its own sqlite implementation that does not depend on 3rd party shared libraries so it's not quite the same thing.

My previous advice to people attempting to do something similar with deno compile is to experiment with WebAssembly - please see https://github.com/lovell/sharp/issues/3912#issuecomment-1866214392

lovell avatar Nov 24 '24 08:11 lovell

Bun provides its own sqlite implementation that does not depend on 3rd party shared libraries so it's not quite the same thing.

My previous advice to people attempting to do something similar with deno compile is to experiment with WebAssembly - please see https://github.com/lovell/sharp/issues/3912#issuecomment-1866214392

Like I wrote in the earlier post; I am not talking about the built-in sqlite library. I am talking about the node-lib of sqlite that also works with Bun. Any case, I now understand the issue. I have opened an issue with the Bun team so that they can include the dynamic lib inside the binary. Thanks!

buzzy avatar Nov 24 '24 09:11 buzzy

My previous advice to people attempting to do something similar with deno compile is to experiment with WebAssembly - please see #3912 (comment)

I patched sharp.js to force the Wasm library to load but, upon invocation, my program froze.

'use strict';
module.exports = require('@img/sharp-wasm32/sharp.node')

Do you know how should I debug this?

Thanks.

LetrixZ avatar Dec 04 '24 04:12 LetrixZ

I got this working as a sort of experiment previously and can probably be done even easier now, with very recent improvements in https://bun.sh/docs/bundler/executables#embed-assets-files. As the sharp .node addon builds fine, the snag is in the libvips dll/so library. After @lovell answered https://github.com/lovell/sharp/issues/4023 it was clear the path for now was doing some imports/scripting to make those files embedded in the binary, and then update the reference from sharp.

infrahead avatar Dec 05 '24 19:12 infrahead

After experimenting I managed to get it working with this:

I use this script to make a file which basically is an import line for the Node module with { type: 'file' }.

// embed-sharp.ts
import { runtimePlatformArch } from './node_modules/sharp/lib/libvips';

const runtimePlatform = runtimePlatformArch();

const path = `./node_modules/sharp/src/build/Release/sharp-${runtimePlatform}.node`;

// eslint-disable-next-line @typescript-eslint/no-require-imports
require(path);
Bun.write('./compile/sharp.ts', `import '${path.replace('./', '../')}' with { type: 'file' }`);
// compile/sharp.ts
import '../node_modules/sharp/src/build/Release/sharp-darwin-arm64.node' with { type: 'file' }

I then import the generated file in my entrypoint:

// entrypoint.ts
...
import './compile/sharp';

...

I needed to patch the Sharp package so it gets the module from the embeded files:

diff --git a/lib/sharp.js b/lib/sharp.js
index 3428c5fefae5c7fc02f18a6a9026ac6a7df190e4..fd8dbff27768dae8242f77eeeb53f4dc910fd0c3 100644
--- a/lib/sharp.js
+++ b/lib/sharp.js
@@ -6,6 +6,7 @@
 // Inspects the runtime environment and exports the relevant sharp.node binary
 
 const { familySync, versionSync } = require('detect-libc');
+const { join } = require('node:path');
 
 const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
 const runtimePlatform = runtimePlatformArch();
@@ -29,6 +30,11 @@ for (const path of paths) {
   }
 }
 
+if (!sharp && Bun.embeddedFiles.length) {
+  const sharpModule = Bun.embeddedFiles.find(file => /sharp-(.*).node$/.test(file.name))
+  sharp = require(join(import.meta.dirname, sharpModule.name));
+}
+
 /* istanbul ignore next */
 if (sharp) {
   module.exports = sharp;

This is my build script:

# build.sh
bun ./embed-sharp.ts &&
bun build --outfile my_binary --minify --sourcemap --compile ./entrypoint.ts

Importing the package @img/sharp-${runtimePlatform}/sharp.node didn't work as then the lib files wouldn't be included. I need to build the module from source else it won't work.

I only tried on macOS ARM64 and Linux x64

LetrixZ avatar Dec 24 '24 20:12 LetrixZ

This might not work. It complains that libvips-cpp.so.42 is missing when trying on a fresh system.

LetrixZ avatar Dec 31 '24 04:12 LetrixZ

i dont think this is exclusively related to bun. i tried with node js pkg and same/similar error messages.

ev3nst avatar Feb 04 '25 03:02 ev3nst

So, no go with bun for now I guess?

Seems I have to run my app directly now instead of the built version, just to get sharp to work, no idea if they intend to address this? Not much performance impact I assume?

ClarenceL avatar Apr 19 '25 19:04 ClarenceL

Sorry to revive a closed thread, potential fix described here https://github.com/lovell/sharp/issues/4377#issuecomment-2819585265

Just a quick update. Found a solution. I was missing --config package.json in the npx command:

npx pkg index.js --config package.json --targets node20-macos-arm64 --output index

And added assets to package.json:

 "pkg": {
    "assets": [
        "node_modules/@img/sharp-darwin-arm64/**/*",
        "node_modules/@img/sharp-libvips-darwin-arm64/**/*"
    ]
}

jo-chemla avatar Aug 21 '25 12:08 jo-chemla

Sorry to revive a closed thread, potential fix described here #4377 (comment)

Just a quick update. Found a solution. I was missing --config package.json in the npx command:

npx pkg index.js --config package.json --targets node20-macos-arm64 --output index

And added assets to package.json:

 "pkg": {
    "assets": [
        "node_modules/@img/sharp-darwin-arm64/**/*",
        "node_modules/@img/sharp-libvips-darwin-arm64/**/*"
    ]
}

Does this works if the user doesn't have libvips installed in their system?


UPDATE: Checked @yao-pkg/pkg and it works by bundling the files and extracting them at runtime to $HOME/.cache and I could only get it working with the prebuilt binaries and not with custom Vips because it can't load libvips-cpp.so.42.

LetrixZ avatar Nov 06 '25 03:11 LetrixZ