electron-builder: Unable to access a file inside asar pacakge

  • Version: 6.7.3
  • Target: Linux, Windows

I have some scripts in my app, which I need to execute when application starts. I am allowing asar packaging in the project. It throws following error at runtime Can't open /tmp/.mount_ryQosd/usr/bin/resources/app.asar/myfolder/subfolder/myscripts/myscript1.sh

This does not happen during development so this seems to be error with asar packaging, not allowing to access the file. Although it’s not preferred but I tried unpacking myscripts folder by adding this in build options "asar": { "unpackDir": "myfolder/subfolder/myscripts" }, it did not work either. I get the same error.

Am I writing the right syntax for unpackDir? Is there any alternative so that script file can be accessed during runtime?

Thanks

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 35 (11 by maintainers)

Most upvoted comments

I understand that it will directly copy the file inside myscripts folder instead of the complete hierarchy. That is as good as just declaring extraResources, I think.

it should work without any modification, in the same way as without packaging.

No, it does not work without modification. Because the required file is in different location after packaging so I think we would need to have two different references, one for after packaging and one for without packaging To give you an overview: I have a js file at app/myfolder/mysubfolder/spawn_script.js which executes the bash scripts in app/myfolder/mysubfolder/myscripts. spawn_script.js is the file where I reference these scripts,

at app/myfolder/mysubfolder/spawn_script.js

  1. If I reference the bash script file using filepath = path.join(__dirname, "myscripts/myscript1.sh") then after packaging filepath==…resourcesDir/app.asar/myfolder/mysubfolder/myscripts/myscript.sh Works without packaging, doesn’t work after packaging(as app.asar is not readable)
  2. If I reference the file using path.join(process.resourcesPath, "app/myfolder/subfolder/myscripts/myscript1.sh") then without packaging i.e. in development filepath==…node_modules/electron-prebuilt/dist/resources/myfolder/mysubfolder/myscripts/myscript.sh Doesn’t work without packaging(as file is not there in resources), works after packaging

Edit Basically final solution looks like this for me

//package.json
"extraResources": "app/myfolder/mysubfolder/mysripts"
//app/myfolder/mysubfolder/spawn_script.js
if(isDevelopment){
     filepath = path.join(__dirname, "myscripts/myscript1.sh");
} else {
     filepath = path.join(process.resourcesPath, "app/myfolder/subfolder/myscripts/myscript1.sh");
}

FWIW I’m also having a painful 1+ day excursion on how to reference a simple file inside the ASAR in the production Node environment. I just wanted to offer some perspective on how I view the problem.

My project is based on https://github.com/chentsulin/electron-react-boilerplate. In my case, I’ve added EJS HTML templates inside my app and want to reference EJS files at runtime to render web pages.

It seems this problem is confusing because there are 3 options:

  1. Use extraResources, keep the files outside the ASAR, and use process.resourcesPath to get the path in production. You have to have an if statement do do different stuff between dev and production, just like @makeitcount did above. This is the easiest option, but it’s kind of dirty if you have a lot of static files you’re trying to reference. Plus splitting logic in code everywhere to differentiate between development and production is error prone.
  2. Use asarUnpack + hazardous. This seems like the best solution if you need to execute a binary. All I’m trying to do is get a simple reference to a file.
  3. Somehow the magic bullet. Keep the file in the ASAR, and have a sane way to access it during development and production.

NOTE: Debugging this is very time consuming and painful because everything works in fine, but breaks in production. This means you have to continue to rebuild using electron-builder, which takes 4-5 minutes on my project. Each time I want to tweak a simple path or logged path, I have to wait 5 minutes for electron-builder to run to see if it worked. That’s why this is so painful and difficult to debug.

Maybe there is an opportunity for electron-builder or electron (not sure) to improve this API in the future. It seems like a great opportunity for a new API like process.asarPath (similar to process.resourcesPath), or app.getAsarFile() (similar to app.getPath()).

One more note: I think the core problem here is that app.getAppPath() returns very different answers between development and production. In development, it’s just pointing to my local Electron version, when I want it to point inside my code. In production, it seems correct, but it’s difficult to use to find an actual file inside the ASAR.

Thanks for the time you put into working on electron. I’m just trying to offer a perspective. I don’t expect anything to be done specially for me here, just trying to give feedback. 🙏

Do you mean I need to write app/myfolder/subfolder/myscripts?

It is better to use extraResources and yes, app/myfolder/subfolder/myscripts

What is the difference between extraResources and asarUnpack? Their behaviour seems the same. I didn’t find good documentation. They both copy files into another folder under resource, and keep another duplicate copy in app.asar. This duplicate copy seems unnecessary.

Thanks @develar, but it will take quite sometime to separate the needed code to share with you. For now I have added extraResources settings, it unpacks the required directory under resources folder. To access these files I have changed my path from path.join(__dirname, "myscripts/myscript.sh") to path.join(process.resourcesPath, "app/myfolder/subfolder/myscripts/myscript1.sh") And as expected this works in final executable but not in development as the process.resourcesPath references the resources folder inside electron-prebuilt

I am using two package json structure.

So, your error is that path is not relative to project base dir. BTW, please consider to use extraResources to copy such files, but not asar.unpackDir

@robot110011 don’t worry on this. Check this

Here’s what I’m using:

  // Get a path to prepend to any nodejs calls that are getting at files in the package,
  // so that it works both from source and in an asar-packaged mac app.
  // See https://github.com/electron-userland/electron-builder/issues/751
  private directoryAdjustment(): string {
    const appPath= app.getAppPath();
    // windows from source: "C:\myapp\node_modules\electron\dist\resources\default_app.asar"
    // mac from source: "/Users/me/dev/myapp/node_modules/electron/dist/Electron.app/Contents/Resources/default_app.asar"
    // mac from a package: <somewhere>"/my.app/Contents/Resources/app.asar"
    if (appPath.indexOf("default_app.asar") < 0) {
      return Path.normalize(appPath+ "/../..");
    } else {
      // If we are run from outside of a packaged app, our working directory is the right place to be.
      // And no, we can't just set our working directory to somewhere inside the asar. The OS can't handle that.
      return "";
    }
  }

Then I use it like this:

const foobDir= fs.realpathSync(
          Path.join(this.directoryAdjustment(), "sample data/foo")

@goldylucks I gave up and just ended up using extraResources instead of trying to put my files inside the ASAR archive.

In main.dev.js I have:

const somePath = isDev
  ? 'file.development'
  : path.join(process.resourcesPath, 'file.production');

foo.bar({ path: somePath });

This works, but it’s undesirable because I have to continually switch between dev and packaged context anytime I want to grab a file.