Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow ASAR to work with child_process.spawn() #9459

Open
sindresorhus opened this issue May 14, 2017 · 10 comments
Open

Allow ASAR to work with child_process.spawn() #9459

sindresorhus opened this issue May 14, 2017 · 10 comments

Comments

@sindresorhus
Copy link
Contributor

sindresorhus commented May 14, 2017

There are Node APIs that can execute binaries like child_process.exec, child_process.spawn and child_process.execFile, but only execFile is supported to execute binaries inside asar archive.

This is because exec and spawn accept command instead of file as input, and commands are executed under shell.

This is not entirely correct. .spawn() executes the binary directly by default, just as .execFile() does. .execFile() actually uses .spawn() underneath. .spawn() only runs the input in a shell if the shell option is set.

Not supporting .spawn() means a lot of apps are not able to use ASAR as they need the more flexible .spawn() method. For example, I need the .spawn() method so I can stream the output of ffmpeg while it's running. .execFile() only buffers and reports at the end.

Would also make sense to support .spawnSync() for completeness.


See #3512 for previous discussion.

@seanzer
Copy link
Contributor

seanzer commented Oct 15, 2017

I get the caveats to supporting spawn, but there are valid use cases that would not be affected by the ASAR. I want to spawn an executable which is not packed in the asar, and to be able to configure the environment. I think it's worth documenting that inspecting the asar from another processes may fail, but at least supporting spawn would enable some of us to be able to use asar.

@sindresorhus
Copy link
Contributor Author

For anyone looking for a temporary workaround, check out: https://github.com/sindresorhus/electron-util#fixpathforasarunpackpath

@nuthinking
Copy link

@sindresorhus how to make the workaround work with electron-packager?

@midevnull
Copy link

midevnull commented Jan 29, 2019

@sindresorhus how can I use your fix with with modules like imagemin-optipng? Is there another way than manualy chage the module and prevent overwrites by the original module.

The weird thing is that imagemin-jpegtran (uses spawn as well) works but imagemin-optipng doesnt.

@Richard-Choooou
Copy link

@sindresorhus Aha, I got this problem too.

@Richard-Choooou
Copy link

@midevnull you can try to set "asar" to false in package.json, like this

"build": {
    "asar": false
  },

@michaeljpeake
Copy link

@midevnull you can try to set "asar" to false in package.json, like this

"build": {
    "asar": false
  },

Or you can use asarUnpack and specify what you want to leave out. Personally, I'm not seeing many benefits from using asar. Willing to be educated in what they are though.

@ayizhi
Copy link

ayizhi commented Feb 3, 2021

pm2 use Client Object in pm2/lib/Client.js to start a Daemon

Client.prototype.launchDaemon = function(opts, cb) {
  ...
  var child = require('child_process').spawn(interpreter, node_args, {
    detached   : true,
    cwd        : that.conf.cwd || process.cwd(),
    env        : util._extend({
      'SILENT'      : that.conf.DEBUG ? !that.conf.DEBUG : true,
      'PM2_HOME'   : that.pm2_home
    }, process.env),
    stdio      : ['ipc', out, err]
  });

};

In theory,this method can be hacked

require('pm2').Client.__proto__.launchDaemon = function (opts, cb) {
  ...
  var ClientJS = path.resolve(path.dirname(module.filename), 'Daemon.js');
  var child = require('child_process').fork(ClientJS, node_args, {
    detached   : true,
    cwd        : that.conf.cwd || process.cwd(),
    env        : util._extend({
      'SILENT'      : that.conf.DEBUG ? !that.conf.DEBUG : true,
      'PM2_HOME'   : that.pm2_home
    }, process.env),
    stdio      : ['ipc', out, err]
  })
}

by this way, we are able to replace launchDaemon by ourself's, in which we can use fork to start Daemon
and if we start Daemon by child_process.fork, asar can be set to "true"

@agentcooper
Copy link

To make my app work with ASAR, I am calling this helper function before the code that uses child_process.spawn:

import * as child_process from "child_process"

/**
 * To be used with 'asarUnpack' option in electron-builder.
 */
export function patchSpawnForASAR(): void {
    const originalSpawn = child_process.spawn

    const asarSpawn = (command: string, args?: string[], options?: object) => {
        return originalSpawn(
            command,
            args ? args.map((arg) => arg.replace("app.asar", "app.asar.unpacked")) : undefined,
            options
        )
    }

    ;(child_process as any).spawn = asarSpawn
}

(paste into https://www.typescriptlang.org/play to get JavaScript version)

@kostas-jonauskas
Copy link

You can include your executables as ExtraResources so they won't get packaged into ASAR archive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants