0

I want to close the Electron App by js.

"electron": "^13.1.7"

I read those questions carefully:

But none of those work for me.


All the below tests are base on the offical electron-quick-start

  1. According to the answers in questions above, I got these code:

index.html

  <body>
    <button id="close-app">
        close
    </button>
    <script src="./renderer.js"></script>
  </body>

main.js

const {BrowserWindow, remote} = require('electron')
...
app.whenReady().then(() => {
  ...
  app.on('activate', function () {
    ...
    document.getElementById("close-app").addEventListener("click", function (e) {
      remote.getCurrentWindow().close()
    })
  })
})

There is just no any effects or errors.

There is just no any effects or errors.

It seems like the code have never been run, I added a console.log('run') above the addEventListener and there is nothing been print in the console.


  1. According to the document, I got these code:

(change nothing of the offical electron-quick-start but only preload.js and index.html)

index.html

as same as above

preload.js

const { app } = require('electron');
window.addEventListener('DOMContentLoaded', () => {
  document.getElementById("close-app").addEventListener("click", function (e) {
      app.quit();
  })
})

got Uncaught TypeError: Cannot read property 'quit' of undefined only Uncaught TypeError: Cannot read property 'quit' of undefined


So, how can I close the Electron App by js?

Thanks a lot for anyone help!

DengSihan
  • 2,119
  • 1
  • 13
  • 40
  • 1
    Your button's id is `close-app`. Try changing `document.getElementById("close").addEventListener` to `document.getElementById("close-app").addEventListener` in main.js – phuzi Jul 22 '21 at 08:27
  • I noticed you updated the question! Was that a typo in the question? or did it match your actual code? – phuzi Jul 22 '21 at 08:29
  • @phuzi Sorry for my careless,I copy the code from my project directly which has many other code may bother the attention. The errors are still there when id is correct. – DengSihan Jul 22 '21 at 08:31

2 Answers2

8

Electron has modules that only work in the main process like app and modules that only work in the renderer process like ipcRenderer and modules that are common and can run in both processes

I recommend reading this article from the Electron docs which explains the process model

Preload scripts contain code that executes in a renderer process before its web content begins loading. These scripts run within the renderer context, but are granted more privileges by having access to Node.js APIs.

Because the app module is a main process module, if you try to access it from the preload script (renderer process), app will be undefined

// in preload.js
const { app } = require('electron');

console.log(app); // undefined

Instead, you should use inter-process communication to tell the main process to quit

// in main.js
const { app, ipcMain } = require('electron');

ipcMain.handle('quit-app', () => {
  app.quit();
});

// in preload.js
const { ipcRenderer } = require('electron');

window.addEventListener('DOMContentLoaded', () => {
  document.getElementById('close-app').addEventListener('click', () => {
      ipcRenderer.invoke('quit-app');
  });
});
aabuhijleh
  • 2,214
  • 9
  • 25
  • Dude, I have spent HOURS reading documentation, other StackOverflow posts, etc. and FINALLY, in 2022, this is a working solution. You are a GOD! – dbrree Feb 02 '22 at 22:42
2

for those who are not using the offical template but a Vue3 webpack based electron.

you have to create the window first in an async function which will return the win created by BrowserWindow()

main.js

import { BrowserWindow, ipcMain } from 'electron'

async function createWindow() {
    // Create the browser window.
    const win = new BrowserWindow({
        transparent: true,
        frame: false,
        webPreferences: {
            nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
            enableRemoteModule: true
        }
    })

    if (process.env.WEBPACK_DEV_SERVER_URL) {
        await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
        if (!process.env.IS_TEST) win.webContents.openDevTools()
    }
    else {
        createProtocol('app')
        // Load the index.html when not in development
        win.loadURL('app://./index.html')
    }

    return win;
}

app.on('ready', async () => {
    createWindow()
        .then(win => {
            ipcMain.on('close-app', () => {
                win.hide();
            });
            ipcMain.on('min-app', () => {
                win.minimize();
            });
        });
});

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    </head>
    <body>

        <span role="control-panel">
            <button type="button"
                id="min-app" 
                aria-label="minimize your app">
                <i class="mdi mdi-window-minimize text-2xl"></i>
            </button>

            <button type="button"
                id="close-app"
                aria-label="close your app">
                <i class="mdi mdi-close text-2xl"></i>
            </button>
        </span>

        <script>
            // for close/min app
            const { ipcRenderer } = require('electron');
            document.getElementById('close-app').addEventListener('click', () => {
                ipcRenderer.send('close-app');
            });
            document.getElementById('min-app').addEventListener('click', () => {
                ipcRenderer.send('min-app');
            });
        </script>
    </body>
</html>
DengSihan
  • 2,119
  • 1
  • 13
  • 40