develar / 7zip-bin

7-Zip precompiled binaries
MIT License
117 stars 34 forks source link

The following error occurred when using `7zip bin` after electron packaging? #14

Open glk-hll opened 3 years ago

glk-hll commented 3 years ago

image

Dumspy commented 2 years ago

So I found one workaround on my environment(Mac OS) "chmod +x 'path of 7za'" which gets things working but I wouldn't call a perfect solution

Anyone found a better way of getting things working

marko-hologram commented 1 year ago

This error says that it cannot execute that particular file because apparently it doesn't exist. The problem here is that app.asar is a special archive type and spawn cannot execute files that are stored there.

One solution for this is to "unpack" 7zip-bin during Electron packaging process and then reference it from that "unpacked" folder.

For example if you use electron-builder, this property in config can be used

{
  "asarUnpack": ["node_modules/7zip-bin"]
}

This tells electron-builder to move these files outside that app.asar archive and into app.asar.unpacked, which is just a regular folder. Then when requiring path to 7zip-bin, some transformation on the required path can be performed.

const asarToAsarUnpacked = (path) => {
  if (!/app\.asar\.unpacked/.test(path)) {
    const pathUnpacked = path.replace(/app\.asar/, "app.asar.unpacked");

    if (existsSync(pathUnpacked)) {
      path = pathUnpacked;
    }
  }

  return path;
};

const sevenZipBinPath = asarToAsarUnpacked(require("7zip-bin").path7za);

Hopefully this helps someone. I got to this solution through various posts, digging through some code for some open source Electron projects and who knows what else 😄


I know this worked for me in the past, but unfortunately it stopped working on one project where I use this technique. Not sure why it happened, but I guess I'm just overlooking something I did with dependency/environment updates in the recent past.

marko-hologram commented 1 year ago

I've managed to resolve my issue by kinda manually pointing to the appropriate binary file.

const getSevenZipBinPath = () => {
  let sevenZipModuleRootPath = "";

  if (App.isDevelopmentMode()) {
    // In development this require.resolve() call resolves to proper path to 7zip-bin entry file, but accessing ".path7za" exported property gives wrong path
    const sevenZipModulePath = require.resolve("7zip-bin");
    // Previous line resolves to "index.js" entry path so we just go back one path fragment to get to the root of the 7zip-bin module folder
    sevenZipModuleRootPath = path.resolve(sevenZipModulePath, "..");
  } else {
    // In production we can just access resources path and construct the rest of the path from there
    sevenZipModuleRootPath = path.join(process.resourcesPath, "app.asar.unpacked", "node_modules", "7zip-bin");
  }

  return path.join(sevenZipModuleRootPath, "win", process.arch, "7za.exe");
};

I do have to worry about Windows only so there is no code here to handle other operating systems, but it wouldn't be hard to add that if necessary.


Not sure what caused issues for me, but googling some stuff it seems like it might be a Webpack thing where Webpack is kinda replacing __dirname or require() calls and thus not resolving to what I would expect. That is possible since I've updated all project dependencies recently and this probably triggered all of this somewhere under the hood.