4

I have an electron app that builds and runs in development, but when packaging the app with electron-builder, the preload script is not packaged in the right location.

This is a well documented issue and there are very similar questions here and here for example, but none of the replies or solutions are working in my case.

From my electron.js file:

function createWindow() {
    const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(app.getAppPath(), 'src/preload.js'),
            contextIsolation: true,
        },
    });

    // In production, set the initial browser path to the local bundle generated
    // by the Create React App build process.
    // In development, set it to localhost to allow live/hot-reloading.
    const appURL = app.isPackaged
        ? url.format({
            pathname: path.join(__dirname, 'index.html'),
            protocol: 'file:',
            slashes: true,
        })
        : 'http://localhost:3000';
    mainWindow.loadURL(appURL);

    mainWindow.webContents.openDevTools();
}

My preload script:

const { contextBridge, shell } = require('electron')

contextBridge.exposeInMainWorld(
    'electron',
    {
        openBrowserWindow: (url) => shell.openExternal(url)
    }
)

And my Electron app package.json:

    "build": {
        "extends": null,
        "appId": "com.app",
        "productName": "App",
        "directories": {
            "output": "dist"
        },
        "mac": {
            "target": {
                "target": "pkg",
                "arch": [
                    "universal"
                ]
            },
            "darkModeSupport": "true",
            "extendInfo": "app"
        },
        "pkg": {
            "installLocation": "/Applications",
            "overwriteAction": "upgrade"
        },
        "files": [
            "**",
            "../app/src/*",
            "src/preload.js"
        ],
        "extraResources": [
            "../app/src/*",
            "src/preload.js"
        ],
        "extraFiles": [
            "../app/src/*",
            "src/preload.js"
        ]
    }

Above I have tried to make sure the "src/preload.js" file is copied over in different ways, but I still get the error:

Unable to load preload script: ...app/Contents/Resources/app.asar/src/preload.js

Error: Cannot find module '...app/Contents/Resources/app.asar/src/preload.js'

The preload script is in fact copied over, but it is not part of the app.asar file. It is copied in to a src folder outside of the Resources folder which contains the app.asar file:

enter image description here

How do I correctly configure electron-builder so this file is in the right location and can be accessed at package runtime?

Mr. Robot
  • 1,334
  • 6
  • 27
  • 79

4 Answers4

2

If you do:

const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
        preload: path.resolve(app.getAppPath(), 'preload.js'),
        contextIsolation: true,
    },
});

Does it works ? (worked for me with electron-webpack and electron-builder)

H3r3zy
  • 86
  • 7
2
        preload: path.join(app.getAppPath(), 'src/preload.js'),

As you are not packaging the preload.js into the app package file (asar default), this won't work like this. app.getAppPath() will indicate the app package file(or directory, in case you are setting asar as false)

Your code is indicating /xxx.app/Contents/Resources/app.asar/src/preload.js or /xxx.app/Contents/Resources/app/src/preload.js Your preload script file is not there but in the 2nd parent's directory.

So here is the correct path in your case,

path.join(app.getAppPath(), '..', '..', 'src', 'preload.js');
tpikachu
  • 4,478
  • 2
  • 17
  • 42
  • will this command copy the node_modules folder into the resources folder? Second will the paths break if I have development paths? https://stackoverflow.com/questions/76397570/expected-app-structure-and-pathing-problems-after-build-of-electron-project-usin – Gary Jun 04 '23 at 05:23
  • 1
    I'm not sure yet but if you wanna pack some specific `node_moduels` please have a look at `extraResources` https://www.electron.build/configuration/contents.html#extraresources – tpikachu Jun 06 '23 at 18:50
  • if i have a path of `project/binaries` in dev which is packed into `resources/binaries` will the paths of my electron files change in the build. second, if i add the `binaries` folder in the `extraResources` setting will it be copied all automatically into the resources folder? Is the extra resources have the `binaries` folder in it or will it be there in the `asar`? – Gary Jun 08 '23 at 01:39
  • It won't copy your `binaries` folder into `asar`. I'd suggest you pack the app and try to have a look inside the packed app. It will make much more sense – tpikachu Jun 09 '23 at 12:15
  • say i pack the app manually copying `binaries` folder into the resources folder like `resources/binaries` then what will the pathing be in such a case. if i put the `binaries` folder in the main `app` folder then i think the `app.getAppPath()` should work I presume? – Gary Jun 10 '23 at 13:12
  • 1
    Yes, it will work – tpikachu Jun 12 '23 at 03:14
2

First, add console logs for testing.

console.log({dirname: __dirname})
console.log({getAppPath: app.getAppPath()})
console.log({resourcesPath: process.resourcesPath})

const mainWindow = new BrowserWindow({ ... })

Second, you have to add contextIsolation: true.

If you are using electron-builder and for some reason you cannot add contextIsolation: true you can use this workaround:

package.json

  "build": {
    ...
    "extraResources": [
      ...
      "app/preload.js" // <---- add your path
    ],
  }

electron.js

const preloadPath =
      process.env.NODE_ENV === 'development'
        ? path.join(__dirname, '../preload.js') // <---- add your path
        : path.join(process.resourcesPath, '/app/preload.js'); // <---- add your path

const mainWindow = new BrowserWindow({
      ...
      webPreferences: {
        contextIsolation: false,
        preload: preloadPath,
        ...
      }
})

What is path.join(process.resourcesPath, '/app/preload.js') ?

After building your app you can find your extra resources here

C:\Users\<user>\AppData\Local\Programs\<app>\resources - for Windows.

For MacOS you can right click on your app and click on Show Package Contents > Resources

Dmitry Grinko
  • 13,806
  • 14
  • 62
  • 86
1

I solved this problem by adding "preload.js" directly to the build -> files list in my package.json - I don't know why that was necessary since it already had "*.json" in it but it fixed the problem for me.

Simon Willison
  • 15,642
  • 5
  • 36
  • 44