I'm trying to prompt an "open file" dialog box, and I found dialog.showOpenDialog(...) in the electron docs.
I've added this line to a few different projects now, with the result of crashing as soon as that line hits. I would see the file explorer dialog window open for a second, then it crashed. The console gives me no error message, the last thing it prints is Promise { <pending> }.
What I've tried:
Adding dialog.showOpenDialog(...) to the official vscode debugging example, to see if it picks up any errors. It always crashes as soon as it reaches that line, with no error message.
Removing my node_modules folder and reinstalling electron using npm install electron --save-dev
Running the app using a global electron command electron .
Uninstalling global electron using npm uninstall -g electron and using a local npm start
Checking if my node packages are out of date using `npm outdate
Running the app using --disable-gpu argument
I'm using Ubuntu 19.04, not a VM, but I also tested it on Ubuntu 18.04 in a VM.
One interesting note is that when I tried to use an html form button with a type = file to accomplish this same task, it also crashed as soon as the file explorer dialog box opened in the electron app. BUT it did work when I opened the html page in a regular web browser.
Here's my main.js
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
win.loadFile('index.html')
// Open the DevTools.
win.webContents.openDevTools()
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null
})
const { dialog } = require('electron')
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] })) //*****THIS LINE HERE
}
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
Here's my package.json
{
"name": "electron-demo",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"electron": "^7.1.2"
}
}
Related
I've recently created an app with a Java backend and a React frontend, and I was using Electron and some Node features to bundle the app and create a desktop app for it. Basically, I decided to use Java for some Java-specific libraries I needed. The app will run on port 8080, with the React/JS stuff being served from the static folder, and the Electron wrapper will use some Node libraries to start up the Java process and then after a few seconds connect to localhost:8080.
This works like a charm about half the time, and the other half instead shows me a white screen with no errors! I have debugged this countless times and the only way to fix it is to force reload the Chromium page which sometimes works, and other times doesn't. Obviously this isn't acceptable for users to do with my app. The problem is, I have run out of ideas as to what could be causing this issue.
Here is my main.js for the electron app
const {app, BrowserWindow} = require('electron')
function createWindow () {
try {
var jarPath = './app.jar';
var kill = require('tree-kill');
var child = require('child_process').spawn('java', ['-jar', jarPath, '']);
let win = new BrowserWindow({width: 1000, height: 730});
setTimeout(function() {
win.loadURL('http://localhost:8080/index.html');
}, 2000);
console.log("PID: " + child.pid);
win.on('closed', function () {
kill(child.pid);
mainWindow = null
}
)
} catch(e) {
console.log(e);
}
}
app.on('ready', createWindow)
Information:
OS: windows 10
Electron Version: Latest
Electron Builder Version: Latest
I am trying to make an app that edits .txt files. I want to get the path of the text file when it is opened with the application (i.e. the user chooses to open the .txt with my app). I have included the following in the build of my package.json:
"fileAssociations": [
{
"name": "Text Files",
"description": "Plain Text File",
"ext": [
"txt"
]
}
],
This makes the application open with the file however how do I get the path of the file that was used to open the app. I know I have to do something with a process.argv however I have no idea how to use this. I have tried the below with no success:
ipcMain.on('get-file-data', function(event) {
var data = null;
if (process.platform == 'win32' && process.argv.length >= 2) {
var openFilePath = process.argv[1];
console.log(data)
win.webContents.send('openFile', openFilePath)
}
});
How can I get the path of the file?
This is the log of the whole process. As we can see here, the second argv is the path of the input file path. So process.argv[1] will be enough to the file path. Not sure why you can't get a path.
Maybe this comes from your ipc event listener. Which means the get-file-data is not fired correctly.
As you can see in this below image,I'm showing this process variable in this browser console. Here is how I exposed process variable to the renderer. But this is just for debug! Recommend not doing this in your production.
preload.js
process.once("loaded", () => {
window.process = process;
});
main.js
mainWindow = new BrowserWindow({
width: 1024,
height: 728,
minWidth: 800,
minHeight: 750,
webPreferences: {
enableRemoteModule: true,
preload: path.join(__dirname, "preload.js"),
}
});
And you can use window.process or process on your renderer
I managed to get the path with the following:
const { remote } = require('electron');
console.log(remote.process.argv[1])
This returns the path of the file used to open the app!
I had an Electron 5 environment running on Windows 7.
Electron 5 was installed in the local node_modules.
I was able to develop and run the application from VSCode.
I ran 'ncu' and opted to upgrade to Electron 7.
This upgraded the electron (from 5.0.0 to 7.1.3) and socket.io modules (from 2.1.0 to 2.3.0).
Now, when running 'electron .', my application starts but exits before the window is rendered.
This is because I set the BrowserWindow to show:false and expose it on the ready-to-show event, which is never sent.
I tried downgrading to Electron 5.0.12 but even after removing node_modules the behavior persisted.
I had a global instance of Electron 7 (7.0.0) but the application was using version 5 per a document.write(process.versions.electron) statement in my HTML.
Regardless, I upgraded the global Electron version to 7.1.3 to match.
I then copied the electron-quick-start file, modified with numerous debug statements. The file is:
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
console.log('READY:create...');
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
console.log('load index...');
mainWindow.loadFile('index-none.html')
// Open the DevTools.
console.log('load devtools...');
mainWindow.webContents.openDevTools()
console.log('set handler...');
// Emitted when the window is closed.
mainWindow.on('closed', function () {
console.log('MAINWIN:Closed...');
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
console.log('created');
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
console.log('onWall-close...');
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', function () {
console.log('onActivate...');
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) createWindow()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
console.log('setting timer');
setTimeout(()=>{
console.log('timing out...');
}, 15000)
console.log('setting timer2');
setTimeout(()=>{
console.log('timing2 out...');
}, 200)
console.log('setting timer5');
setTimeout(()=>{
console.log('timing5 out...');
}, 500)
console.log('setting timer7');
setTimeout(()=>{
console.log('timing7 out...');
}, 700)
setTimeout(()=>{
console.log('timing10 out...');
}, 1000)
setTimeout(()=>{
console.log('timing12 out...');
}, 1200)
setTimeout(()=>{
console.log('timing15 out...');
}, 1500)
setTimeout(()=>{
console.log('timing17 out...');
}, 1700)
The HTML file is:
<html>
<head><title>title</title></head>
<body>
Hello world.
</body>
</html>
When I run either "electron eqs.js" or ".\node_modules.bin\electron.cmd eqs.js" I get this output:
setting timer
setting timer2
setting timer5
setting timer7
READY:create...
load index...
load devtools...
set handler...
created
timing2 out...
timing5 out...
timing7 out...
timing10 out...
timing12 out...
timing15 out...
(Sometimes timing15 doesn't get printed).
In this case I see the BrowserWindow get created, but it remains blank. The developer tools do not open. Commenting out the line opening the developer tools changes nothing.
This behavior happens with both:
C:\electron\electron-quick-start>.\node_modules.bin\electron.cmd -v
v5.0.12
C:\electron\electron-quick-start>electron -v
v7.1.3
I don't understand why the process is exiting while timers are active, so something somewhere must be calling app.exit() or similar. Besides "What is going on?", my obvious question is: how do I fix this?
I don't have an actual answer to this problem, but it was fixed when I upgraded to Electron 7.1.9 as I commented in the bug report https://github.com/electron/electron/issues/21544#issuecomment-577242668
During the upgrade some process took an unusually long time to complete but when it did my application ran successfully. I was also able to downgrade to a previous version of Electron and my application still ran, even when using a version that was failing earlier.
EDIT:
This problem resurfaced when an attempt to upgrade to Electron 8.2.2 failed because the application was running in a debugger. Unfortunately, no amount of version up/down-grades (up to 8.2.3) was able to recover the environment. Ultimately, disabling the sandboxing from my package.json launch script allowed me to proceed. This is the new command structure:
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Electron: Main",
"protocol": "inspector",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"runtimeArgs": [
"--remote-debugging-port=9223",
"--no-sandbox", <<<<<-- PASS THIS COMMAND OPTION
"."
],
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
}
},
[...]
]
For anyone stumbling across this: I had a similar problem.
Deleting the local files on Windows under %appdata%/YOUR_APP_NAME fixed Electron failing to launch properly for me.
I did the following in my index.js;
electron.remote.app.on("open-url", function(event, url) {
console.log("Open URL: " + url);
});
This gets triggered in Mac OS, but not in Windows. Is there another event or a different way to do it in windows?
From mine similar Q/A at SO:
It's about opening app and pass parameters with deep linking using Electron for both platforms (macOS/win32).
Minimal electron project with deep linking capabilities in macOS/win32 platforms (Single Instance Application) 'electron-deep-linking-mac-win' on GitHub.
package.json:
{
"name": "electron-deeplinking-macos-win32",
"version": "0.0.1",
"description": "Minimal Electron application with deep inking (macOS/win32)",
"main": "main.js",
"scripts": {
"start": "electron .",
"pack": "build --dir",
"dist": "build"
},
"repository": "https://github.com/oikonomopo/electron-deep-linking-osx",
"author": "oikonomopo",
"license": "CC0-1.0",
"devDependencies": {
"electron": "1.6.6",
"electron-builder": "17.1.2"
},
"build": {
"appId": "oikonomopo.electron-deeplinking-macos-win32",
"protocols": {
"name": "electron-deep-linking",
"schemes": ["myapp"]
},
"mac": {
"category": "public.app-category.Reference"
},
"win": {
}
}
}
main.js:
const {app, BrowserWindow} = require('electron')
// Module with utilities for working with file and directory paths.
const path = require('path')
// Module with utilities for URL resolution and parsing.
const url = require('url')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
// Deep linked url
let deeplinkingUrl
// Force Single Instance Application
const shouldQuit = app.makeSingleInstance((argv, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
// Protocol handler for win32
// argv: An array of the second instance’s (command line / deep linked) arguments
if (process.platform == 'win32') {
// Keep only command line / deep linked arguments
deeplinkingUrl = argv.slice(1)
}
logEverywhere("app.makeSingleInstance# " + deeplinkingUrl)
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
})
if (shouldQuit) {
app.quit()
return
}
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600})
// and load the index.html of the app.
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
// Open the DevTools.
mainWindow.webContents.openDevTools()
// Protocol handler for win32
if (process.platform == 'win32') {
// Keep only command line / deep linked arguments
deeplinkingUrl = process.argv.slice(1)
}
logEverywhere("createWindow# " + deeplinkingUrl)
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// Define custom protocol handler. Deep linking works on packaged versions of the application!
app.setAsDefaultProtocolClient('myapp')
// Protocol handler for osx
app.on('open-url', function (event, url) {
event.preventDefault()
deeplinkingUrl = url
logEverywhere("open-url# " + deeplinkingUrl)
})
// Log both at dev console and at running node console instance
function logEverywhere(s) {
console.log(s)
if (mainWindow && mainWindow.webContents) {
mainWindow.webContents.executeJavaScript(`console.log("${s}")`)
}
}
main.js code description:
At let deeplinkingUrl we keep the provided url.
At macOS platform this is captured at 'open-url' event, we set it with deeplinkingUrl = url! (See // Protocol handler for osx)
At win32 platform this is saved at process.argv together with other arguments. To get only the provided url, deeplinkingUrl = argv.slice(1). (See // Protocol handler for win32)
As #Aurélien Nicolas mentions, at app.makeSingleInstance method we check in which platform we are and we set deeplinkingUrl accordingly! If we are at win32 platform, the url is located at argv variable from callback, else at macOS should have already been set at 'open-url' event! (See // Force Single Instance Application)
This is a mac-only feature.
The closest alternative is app.makeSingleInstance(callback).
You can arrange for your app to be launched with the url as argument: myApp my-scheme://stuff
Then callback is called with the url in whichever app process was launched first.
I tried to create an application with Node-Webkit and Sails.js. My API works fine, I get the JSON I need, but when integrated with Node-Webkit does not start the server.
My package.json contains:
{
"name": "app-sails"
"main": "front/index.html"
"window": {
"toolbar": true,
"width": 1024,
"height": 600,
"title": "Test Application"
},
"scripts": {
"start": "node server/app.js"
}
}
The index.html is the main page you get when you use the generator angular.js yeoman and contains calls to the server that I have with sails.js. In the web running, but not with Node-Webkit.
When I run the .nw, I can see my index.html correctly; but without the data it throws the sails server.
I appreciate any help.
I recently wrote a small article on this, you can check it out here: https://medium.com/unhandled-exception/sailsjs-and-node-webkit-4ccb8f810add
Basically you just need to execute sails using require as soon as the node-webkit window is loaded. This goes in your app.js file:
exports.onLoad = function() {
var nwGUI = window.require('nw.gui');
nwGUI.Window.get(window).on('loaded', function() {
if (loaded) {
return;
}
window.location.href = "http://localhost:1337/";
loaded = true;
});
try {
sails = require('sails');
} catch (e) {
console.error('To run an app using `node app.js`, you usually need to have a version of `sails` installed in the same directory as your app.');
console.error('To do that, run `npm install sails`');
console.error('');
console.error('Alternatively, if you have sails installed globally (i.e. you did `npm install -g sails`), you can use `sails lift`.');
console.error('When you run `sails lift`, your app will still use a local `./node_modules/sails` dependency if it exists,');
console.error('but if it doesn\'t, the app will run with the global sails instead!');
return;
}
// Try to get `rc` dependency
try {
rc = require('rc');
} catch (e0) {
try {
rc = require('sails/node_modules/rc');
} catch (e1) {
console.error('Could not find dependency: `rc`.');
console.error('Your `.sailsrc` file(s) will be ignored.');
console.error('To resolve this, run:');
console.error('npm install rc --save');
rc = function() {
return {};
};
}
}
// Start server
sails.lift(rc('sails'));
}
and this on your .html entry point:
<html>
<head>
<title>Welcome!</title>
</head>
<body onload="process.mainModule.exports.onLoad();">
<h1>hi!</h1>
</body>
</html>
As you can see, most of that app.jss file is basically the same that comes out when you do a
sails new
I just wrapped everything up and executed that callback onload
If you want you can always check out the article and the full github repo for a more detailed version of the code.
Oh! And don't forget to update your package.json and add:
{
...
"node-main": "app.js",
...
}
You should load the Sails-Page not your index.html.
One thing you could do is (in your HTML)
window.location.href = "http://localhost:1337/";