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
Am I writing the right syntax for unpackDir?
Path must be relative to project base dir (do you use two-package.json structure? in this case please prepend app dir name to path). Or, just myscripts
.
@develar the path is relative to the app directory which I have written. Script is at app/myfolder/subfolder/myscripts/myscript.sh
I am using two package json structure.
Do you mean I need to write app/myfolder/subfolder/myscripts
?
/tmp/.mount_ryQosd/usr/bin/resources/app.asar/myscripts/myscript1.sh
It seems app name is missed here. Please ensure that your path is correct (in your code where do you use it).
UPDATE: sorry, I am wrong, all is ok here.
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
Do you mean I need to write app/myfolder/subfolder/myscripts?
It is better to use extraResources and yes, app/myfolder/subfolder/myscripts
Just tried app/myfolder/subfolder/myscripts
, also tried just myscripts
. It did not work, same error.
Let me try extraResources. Will update you.
Thanks
Exhausted all my options to make it work. Please help.
Aim is to make scripts file readable anyhow, using asar packaging is mandatory.
Please send me your project (of course, if it is private, you can remove all not required data and leave only bare minimum). [email protected]
I used extraResources. I can see that the said folder app/myfolder/subfolder/myscripts
is copied exactly similar way it was in the project.
Now only thing left is to reference these files correctly, how can I reference these files in the project? Is there any api to get resources folder path?
Is there any api to get resources folder path?
Hmm.... it should work without any modification, in the same way as without packaging. Maybe https://github.com/electron-userland/electron-builder/wiki/Options#source-and-destination-directories will be required for you.
Your task is very simple and I don't understand why it is so complex for you, if you can attach your project — please do and I will check what's wrong.
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
And as expected this works in final executable but not in development as the process.resourcesPath references the resources folder inside electron-prebuilt
Please set Destination Directory.
[
{
"from": "app/myfolder/subfolder/myscripts",
"to": "myscripts",
}
]
...and your script will be copied to myscripts
. Without app/myfolder/subfolder
. Exactly as you want.
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
filepath = path.join(__dirname, "myscripts/myscript1.sh")
then _after packaging_ _filepath==....resourcesDir/app.asar/myfolder/mysubfolder/myscripts/myscript.sh_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_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");
}
@develar: I think I have the same problem.
I'm trying to use the library spotify-node-applescript and the dev console returns Error: osascript: node_modules/spotify-node-applescript/lib/scripts/get_track.applescript: No such file or directory
on packaged app.
I added "extraResources": "node_modules/**/**/*.applescript"
, it does copy to the Resources
folder but I'm not sure from where the spotify-node-applescript
is being called to change the path in the library, it is using __dirname
on the code which returns node_modules/spotify-node-applescript/lib
.
I'm also using webpack to bundle everything but I'm not sure if it's related to that problem since it works on dev build.
Edit: this happens with "asar": true
and "asar": false
.
Here's a github respository using electron-webpack and hitting the same issue: https://github.com/lucasbento/electron-webpack-issue.
You can see that it works with yarn dev
but not with yarn dist
.
@lucasbento please use asarUnpack and https://www.npmjs.com/package/hazardous
@develar: thank you for replying.
I added this:
// package.json
"build": {
"asarUnpack": "node_modules/spotify-node-applescript"
},
and hazardous
but didn't work, it throws the same error.
I'm using the same structure as in https://github.com/lucasbento/electron-webpack-issue.
@develar: anything else that I can try?
I will check your case 22 September, I am on vacation.
@develar: omg, so sorry, don't worry about this, have fun on your vacation!
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:
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.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.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. 🙏
@aguynamedben i'm using https://github.com/chentsulin/electron-react-boilerplate as well, couldn't get hazardous
to work. Can you share your code?
I have a call to a node module inside main.dev.js
, and that node module is using __dirname
, which points to app.asar
instead of app.asar.unpacked
@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.
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:
```javascript
const foobDir= fs.realpathSync(
Path.join(this.directoryAdjustment(), "sample data/foo")
any update on this? still having issues between dev and prod envs
@robot110011 don't worry on this. Check this
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 atapp/myfolder/mysubfolder/spawn_script.js
_which executes the bash scripts_ inapp/myfolder/mysubfolder/myscripts
. spawn_script.js is the file where I reference these scripts,at
app/myfolder/mysubfolder/spawn_script.js
- 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)- 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 packagingEdit
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"); }
By providing extraResources in package.json and in path.join(process.resourcePath, 'path') it worked. Thanks @makeitcount .
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.
@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.
I don’t
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")
I don’t understand why you don’t just supply the appPath with two directory levels removed from the end?
Why bother with the function?
Most helpful comment
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.
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_ inapp/myfolder/mysubfolder/myscripts
. spawn_script.js is the file where I reference these scripts,at
app/myfolder/mysubfolder/spawn_script.js
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)
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