-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Possible install-time or require-time problem
- I have read and understood all of the documentation relating to installation.
- I have searched for known bugs relating to this problem in my choice of package manager.
You must confirm both of these before continuing.
Are you using the latest version of sharp?
I first tried with the latest version (0.34.1), but saw here some current issues, so now I'm trying 0.33.5 instead.
Are you using a supported runtime?
- I am using Node.js with a version that satisfies
^18.17.0 || ^20.3.0 || >=21.0.0: v22.14.0
Are you using a supported package manager and installing optional dependencies?
- I am using pnpm >= 7.1.0 with
--no-optional=false: 10.6.5
What is the complete error message, including the full stack trace?
What is the complete output of running npm install --verbose --foreground-scripts sharp in an empty directory?
What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp?
First of all, thank you for the amazing library!
I’m packaging my app using Webpack and generate a single server.mjs file along with the necessary *.node binaries. This helps significantly reduce the size of my Docker image (few MBs vs. ~700MB). This approach previously worked well with sharp, even in Lambda environments.
However, I've noticed some changes that seem to interfere with this setup.
I’ve read through the documentation on pnpm and webpack. However, when using:
externals: {
'sharp': 'commonjs sharp'
}...this assumes the library is discoverable at runtime, typically via node_modules. But in my setup, after bundling, that’s not the case.
From what I understand, this limitation stems from the way prebuilt binaries are resolved:
const paths = [
`../src/build/Release/sharp-${runtimePlatform}.node`,
'../src/build/Release/sharp-wasm32.node',
`@img/sharp-${runtimePlatform}/sharp.node`,
'@img/sharp-wasm32/sharp.node'
];
let sharp;
const errors = [];
for (const path of paths) {
try {
sharp = require(path);This dynamic resolution makes it difficult for bundlers to include the relevant .node binaries, as these paths aren’t statically analyzable.
A possible workaround would be to hardcode the potential paths to make them discoverable during bundling, for example:
let sharp = undefined;
try { sharp = require(`../src/build/Release/sharp-linux-x64.node`,); } catch {...}
if (!sharp) try { sharp = require(`../src/build/Release/sharp-linux-arm.node`,); } catch {...}
if (!sharp) try { sharp = require(`../src/build/Release/sharp-linux-arm64.node`,); } catch {...}
if (!sharp) try { sharp = require(`@img/sharp-linux-x64/sharp.node`,); } catch {...}
[...]Yes, it's tedious and not very elegant, but I haven’t found a better solution so far. I think it's acceptable to start with an initial list and expand it as needed.
Additionally, we could fall back to the current dynamic require logic at the end, preserving backward compatibility.
Does this approach make sense? Am I missing a better alternative?
Thanks again for the great work on sharp!