Search code examples
reactjselectronviteelectron-forge

Electron - React app __dirname is not defined


I have an electron app that I'm packaging with vite using the forge template. I'm having trouble pulling in the ipcRenderer into the React files as it crashes the app with this error:

Uncaught ReferenceError: __dirname is not defined
    at node_modules/electron/index.js (electron.js?v=fee19837:36:30)
    at __require (chunk-CEQRFMJQ.js?v=fee19837:11:50)
    at electron.js?v=fee19837:54:16

I've tried different approaches to fix this but still no luck:

  • Using import.meta.url:
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
  • Using vite.config.js:
export default defineConfig({
  plugins: [
    commonjs(),
    NodeGlobalsPolyfillPlugin({
      process: true,
      buffer: true,
    }),
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  define: {
    'process.env': {},
    '__dirname': '__dirname', // This is a simple way to inject __dirname
  },
});
  • Exposing ipcRenderer in preload.ts:
contextBridge.exposeInMainWorld('ipcRenderer', ipcRenderer)
  • Using browserify in vite config
alias: {
  '@': path.resolve(__dirname, './src'),
  path: 'path-browserify'
}

None of them work and I still get the same error.

Here is my tsconfig:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "commonjs",
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "noImplicitAny": true,
    "sourceMap": true,
    "baseUrl": ".",
    "outDir": "dist",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "jsx": "react-jsx",
    "paths": {
      "*": ["node_modules/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"],
}

I'm using Electron v30.0.9


Solution

  • When you get this error on an Electron app, it usually means you are trying to use electron APIs on your renderer process (i.e. your React code). The variable __dirname is a Node.js global, which require access to the Node.js APIs to be used. And for security reasons, access to Node.js from your renderer is disabled by default.

    To solve this issue, you absolutely do not need to change any config, and please do not try to disable security either. Remove any calls to electron (and Node.js APIs) from your renderer, and use the APIs only via the preload file and IPC.

    Make sure to read the IPC tutorial carefully. Doing this:

    contextBridge.exposeInMainWorld("ipcRenderer", ipcRenderer);
    

    Is bad practice and not secure.


    Furthermore, the only reason why you may need to use:

    import { fileURLToPath } from "url";
    import path from "path";
    
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = dirname(__filename);
    

    Is when your app is ESM and you need __dirname to configure your BrowserWindow on the main process.