I am working on a NodeJs application which helps the developers in my company with the development of our Electron-based product. It does some automatization and at the end, it starts the Electron-app automatically.
Starting the Electron app from inside NodeJs is not a problem. normally the apps are started with a bash script which looks like:
#!/bin/sh
HOME=$PWD/home-dir ./node_modules/.bin/electron myAppDir
myAppDir is the directory with my Electron-App, could be a JavaScript file as well.
Worth to mention, that ./node_modules/.bin/electron is just a symlink to ./node_modules/electron/cli.js
I did following:
const app = execFile('/the/path/to/the/bash/script', [], {
windowsHide: true,
},(error, stdout, stderr) => {
if (error) {
throw error;
}
warn('The app was terminated');
});
This starts the app just fine. However if I do app.kill('SIGTERM'); it outputs the 'The app was terminated' but the app itself does not close.
I tried to execute the node_modules/.bin/electron or the ./node_modules/electron/cli.js instead:
const app = execFile('/the/path/to/node_modules/.bin/electron', ['myAppDir'], {
windowsHide: true,
detached: true,
env: {
HOME: 'path/to/home'),
}
I can launch the Electron app but again - it does not close the running app when I do app.kill('SIGTERM');
EDIT:
My assumption is, that the electron launcher actually spawns a new subprocess, thus killing the launcher does not stops the actual launched app.
This is the content of ./node_modules/.bin/electron (or ./node_modules/electron/cli.js respectively)
#!/usr/bin/env node
var electron = require('./')
var proc = require('child_process')
var child = proc.spawn(electron, process.argv.slice(2), {stdio: 'inherit'})
child.on('close', function (code) {
process.exit(code)
})
You can use this library in you node app https://www.npmjs.com/package/systeminformation and with its .processes(cb) method find running electron app and kill it in the callback of the processes method.
Related
Okay, so when I run the following spawnBot() function in an Electron window, cd throws an error saying that the requested resource could not be found. The following code is part of a file located at /toggle-gui/scripts.js, the electron window page is located at /toggle-gui/pages/index.html and I want to cd into /toggle-gui/imported_bots/toggle-base.
const { spawn } = require('child_process');
const { ipcRenderer } = require('electron');
var selectedBotDir = "./imported_bots/toggle-base";
var bot;
function spawnBot(){
console.log("Attempting to start Toggle...")
console.log("Currently selected bot directory: " + selectedBotDir)
try{
bot = spawn(`cd ${selectedBotDir}; npm install; npm start`, {shell: true, detached: true});
console.log("Process ID: " + bot.pid);
bot.stdout.on('data', data => {
console.log(data);
});
bot.stderr.on('data', data => {
console.log("ERROR: " + data);
});
return bot;
}
catch(error){
console.log(error);
console.log("Toggle failed to start. There should be extra logging output above.")
}
}
Some help here would be greatly appreciated.
The use of ./ in paths makes them relative, which means "treat this path as a subdirectory of the directory you're currently in." However, this "directory you're currently in" does not have to be the directory your Node.js code is located in but rather the directory the shell process you're creating using spawn () was spawned in, which, by default will be set to the directory you're running your Electron app from (i.e. where you ran npm run and not where your script is located).
Thus, you have to tell Node.js in what directory the shell process executing your OS code should be run in, which can be done by passing a cwd (current working directory) parameter to span () as stated in its documentation. The current script's directory can be accessed in Node.js using __dirname, which would lead to the following code:
bot = spawn(`cd ${selectedBotDir}; npm install; npm start`, {shell: true, detached: true, cwd: __dirname});
However, using this method you can get rid of the cd step entirely as you can directly set the cwd to be equal to selectedBotDir, given that that path actually starts with the current directory:
var selectedBotDir = `${__dirname}/imported_bots/toggle-base`;
// ...
try {
bot = spawn(`npm install; npm start`, {shell: true, detached: true, cwd: selectedBotDir});
// ...
} // ...
Please be aware, however, that this could break in multiple ways once you decide to package and distribute your app. By default, Electron apps will be packed into TAR-like archives, ASAR files, which will then be the __dirname. However, the OS cannot directly read from ASAR files and will once again fail to "find the requested resource". Also, if you're planning to distribute your app, don't expect users to also have NPM installed.
I try to start and stop a Tomcat instance on Windows using Electron.
I have modified the electron-quick-start project to stop my Tomcat instance with a batch file which calls Tomcat's shutdown.bat when all Electron windows are closed or before my application exits.
However, when I close my application, there is no output from the shutdownTomcat.on ("data", ...) and shutdownTomcat.on ("exit", ...) listeners. The only output is from a console.log ("Hello world") from my app.on ("before-quit", ...).
I chose this approach because I am new to Electron and want to test NodeJS' spawn's behaviour.
When I use my code outside of the app.on () listeners, the output is shown but my Tomcat instance is not being stopped. However, my startTomcat.bat file, which calls Tomcat's startup.bat, works without any problems.
I already read NodeJS' childProcess' documentation ("Spawning .bat and .cmd files on Windows"), but I cannot get it to work; which leads to my question, namely where the problem is and what I'm doing wrong.
My Main.js file I use for the main process:
const { app, BrowserWindow } = require('electron');
const { spawn } = require('child_process');
const path = require('path');
const start = path.resolve("./start.bat");
const startTomcat = spawn('cmd.exe', ['/c', start], {
cwd: process.cwd(),
detached: true,
});
// ...
app.on('before-quit',()=> {
const shutdownTomcat = spawn('cmd.exe', ['/c', stop], {
detached: true
// stdio: 'ignore'
});
shutdownTomcat.stdout.on('data', (data) => {
console.log("This data won't show up...", data);
});
shutdownTomcat.stderr.on('data', (data) => {
console.log(data.toString());
});
shutdownTomcat.on('exit', (code) => {
console.log(`Child Shutdown Tomcat exited with code ${code}`);
});
console.log("Hello World");
});
And finally, the batch file (stop.bat) I'm using to call Tomcat's shutdown.bat:
cd /D "%~dp0"
cd "..\\apache-tomcat\\bin"
call shutdown.bat
Most probably your electron application is already terminated by the time your events would have fired. Therefore there is no longer reference to your spawned process and listeners.
You can try event.preventDefault() to cancel the app quitting. Then you can explicitly app.quit() once you are done (but beware of infinitely looping through your before-quit listener; you may remove it or app.exit(0)).
I am building an app based on electron vue. My electron app is supposed to start its backend running from a docker container. To do this I call a bash file with the docker run command in it.
const {spawn} = require('child_process')
const dckrrn = spawn('sh', dockercall)
dckrrn.stdout.on('data', (data) => {
console.log(`stdout: ${data}`)
})
dckrrn.stderr.on('data', (data) => {
console.log(`stderr: ${data}`)
})
dckrrn.on('close', (code) => {
console.log(`child process exited with code ${code}`)
})
Everything works fine in development mode but when I try it in my packaged app it complains:
stderr: pathtobashscript.sh line 13 docker: command not found.
It seems for some reason the spawned child process is unaware of the docker installation on the system. What am I doing wrong? What is the correct way to achieve this? Should I try the execfile function? Thanks for your time!
PS:
Sorry that I cannot provide you with a reproducible example, the total app with backend is around 7gb.
PPS:
some interesting sidenotes:
which docker
returns nothing, and:
pwd
returns: /
PPPS: I tried including the docker path at the beginning of my bash script but with no success:
PATH="/usr/local/bin/docker:${PATH}"
export PATH
4PS:
I managed to get the docker running by adding shell: true to the environment. The problem I have now is that the docker folder mappings do not work anymore. So I guess I also have to make them visible to the env somehow.
const {spawn} = require('child_process')
const dckrrn = spawn('sh', dockercall, {
env: {
shell: true
}
})
solved by adding shell: true to the env:
const {spawn} = require('child_process')
const dckrrn = spawn('sh', dockercall, {
env: {
shell: true
}
})
My goal is to do the following steps in my "bundle" process to export an electron app:
open meteor directory
run meteor
when meteor is listening, open the meteor shell
pass the "electrify" command to meteor shell
when electrify build is complete, return.
So far, I have the following
require('shelljs/make');
require('shelljs/global');
var path = require('path');
target.all = function () {
target.bundle();
}
target.bundle = function () {
console.log('Building for architecture: ' + process.platform + platform.arch);
var meteorPath = path.join(__dirname, 'meteor');
cd(meteorPath);
// this runs for a while, make it asyncronous
var meteorCommand = exec('meteor', { async: true });
meteorCommand.stdout.on('data', function (data) {
// ???
});
}
This yields expected output to stdout.
Building for: darwinx64
[[[[[ ~/Code/test/meteor-test ]]]]]
=> Started proxy.
=> Started MongoDB.
=> Babel active on file extensions: es6.js, es6, jsx
I20150728-10:06:05.899(-4)? electrify: installing electrified dependencies
I20150728-10:06:07.005(-4)? electrify: launching electron
=> Started your app.
=> App running at: http://localhost:3000/
However, I am facing a problem... meteor has a startup process and needs to be running before I can use meteor shell, which is the final step where it says "App running at:".
How can I wait for this event to happen before opening the meteor shell?
I have a net.connect script that I am attempting to install as a service on a Windows XP machine.
The application installs correctly using NSSM prior to my attempt to include forever-monitor.
It also works correctly when launching the forever-monitor script manually.
I have attempted to install forever-monitor local to the app and globally but either way produces the same result.
The service installs and then immediately pauses. It will not start.
Can anyone see what I am doing wrong?
The Forever-Monitor code:
// nstream.js
var forever = require('forever-monitor');
var child = new (forever.Monitor)('nstream.0.0.3.js', {
silent: true,
});
child.on('exit', function () {
});
child.start();
Issuing the NSSM command from CMD prompt:
c:\avl\src\nssm.exe install "Test" "c:\program files\nodejs\node.exe" "c:\avl\bin\nstream\nstream.js"
The solution, it turns out, is to add the sourceDir option:
// nstream.js
var forever = require('forever-monitor');
var child = new (forever.Monitor)('nstream.0.0.3.js', {
silent: true,
sourceDir: 'c:/avl/bin/nstream'
});
child.on('exit', function () {
});
child.start();