Search code examples
javascriptnode.jsvue.jselectronipc

IPC in electron renderer throws error from missing function __dirname


I wanted to use the following code to send a message from the renderer to the main process, which then writes it to a log file using electron-log. My main.js looks like this:

import { app, protocol, BrowserWindow } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const { ipcMain } = require('electron');
const log = require('electron-log');
const isDevelopment = process.env.NODE_ENV !== 'production'

// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
  { scheme: 'app', privileges: { secure: true, standard: true } }
])

async function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    frame: true,
    width: 400,
    height: 800,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      enableRemoteModule: false
    }
  })

  ipcMain.on('infoLog', (event, args) => {
    log.info(args)
   });
....

Now I tried to address the IPC in my App.vue accordingly:

import Navbar from '@/components/Navbar'
const { ipcRenderer } = require('electron')

export default {
  name: 'App',
  components: {
    Navbar
  },
  created: function () {
    ipcRenderer.send('infoLog','A async message to main')
  }
}

When I start it with yarn electron:serve I see this error in the console of the window:

Uncaught ReferenceError: __dirname is not defined
    at eval (webpack-internal:///./node_modules/electron/index.js:4)
    at Object../node_modules/electron/index.js (chunk-vendors.js:2778)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader-v16/dist/index.js?!./src/App.vue?vue&type=script&lang=js:5)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader-v16/dist/index.js?!./src/App.vue?vue&type=script&lang=js (app.js:938)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (webpack-internal:///./src/App.vue?vue&type=script&lang=js:2)
    at Module../src/App.vue?vue&type=script&lang=js (app.js:1099)

What I don't understand is that I set it up exactly like Electron's doc:

https://www.electronjs.org/docs/api/ipc-main


Solution

  • You have 2 different issues here:

    • the correct webpack configuration to support node.js code
    • missing node integration to use node API like require

    The stacktrace you are seeing here likely comes from an incorrect webpack configuration. Unless told otherwise, webpack tries to replace __dirname with something different. Here we don't want that - node provides __dirname and we want to use it, so we have to tell webpack to leave __dirname alone.

    You'll find an example in the webpack documentation.

    For webpack 5 adding a node section should help:

    module.exports = {
      //...
      node: {
        global: false,
        __filename: false,
        __dirname: false,
      }
    };
    

    After you solved this problem you'll likely fall over the issue that your browser window does not know require. You can reintroduce specific node API like the IPC by using a preload script. Don't activate the full node integration without knowing what you are doing.

    For an example, have a look at this answer.