diff --git a/package.json b/package.json index 5c05cff..6fc6760 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,8 @@ "asarUnpack": [ "node_modules/ffmpeg-static/**", "node_modules/sharp/**", + "node_modules/@img/**", + "node_modules/@napi-rs/**", "assets/fonts/**" ], "extraFiles": [], diff --git a/tests/packaging-sharp.test.js b/tests/packaging-sharp.test.js new file mode 100644 index 0000000..7090495 --- /dev/null +++ b/tests/packaging-sharp.test.js @@ -0,0 +1,62 @@ +const fs = require('fs'); +const path = require('path'); + +// Regression guard for the deb startup crash (2026-08-23): the packaged build +// pruned the @img/sharp-* native bindings (only the pure-JS @img/colour entries +// landed in the asar), so sharp's loader fell back to a binding that links +// against system libvips and the main process died on ERR_DLOPEN_FAILED before +// any window opened. When a linux build is present, the prebuilt sharp packages +// — including the bundled libvips shared libraries — must be unpacked next to +// the asar (build.asarUnpack claims node_modules/@img/** and node_modules/@napi-rs/**). +const UNPACKED_IMG_DIR = path.join( + __dirname, + '..', + 'dist', + 'linux-unpacked', + 'resources', + 'app.asar.unpacked', + 'node_modules', + '@img' +); + +const buildOutputExists = fs.existsSync(UNPACKED_IMG_DIR); + +function listFilesRecursively(dir) { + const files = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...listFilesRecursively(full)); + } else { + files.push(full); + } + } + return files; +} + +(buildOutputExists ? describe : describe.skip)('packaged @img sharp prebuilt binaries', () => { + test('unpacked @img directory exists and is non-empty', () => { + const entries = fs.readdirSync(UNPACKED_IMG_DIR); + expect(entries.length).toBeGreaterThan(0); + }); + + test.each(['sharp-linux-x64', 'sharp-libvips-linux-x64'])( + '%s package is unpacked with contents', + (pkg) => { + const pkgDir = path.join(UNPACKED_IMG_DIR, pkg); + expect(fs.existsSync(pkgDir)).toBe(true); + expect(listFilesRecursively(pkgDir).length).toBeGreaterThan(0); + } + ); + + test('sharp-linux-x64 ships its native binding', () => { + const binding = path.join(UNPACKED_IMG_DIR, 'sharp-linux-x64', 'lib', 'sharp-linux-x64.node'); + expect(fs.existsSync(binding)).toBe(true); + }); + + test('sharp-libvips-linux-x64 ships the bundled libvips shared libraries', () => { + const libvipsLibDir = path.join(UNPACKED_IMG_DIR, 'sharp-libvips-linux-x64', 'lib'); + const sharedLibs = fs.readdirSync(libvipsLibDir).filter((f) => /^libvips.*\.so/.test(f)); + expect(sharedLibs.length).toBeGreaterThan(0); + }); +});