Mr. Robot
Mr. Robot

Reputation: 1824

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

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?

Upvotes: 4

Views: 4349

Answers (4)

Simon Willison
Simon Willison

Reputation: 15882

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.

Upvotes: 1

Dmitry Grinko
Dmitry Grinko

Reputation: 15214

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

Upvotes: 2

tpikachu
tpikachu

Reputation: 4854

        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');

Upvotes: 2

H3r3zy
H3r3zy

Reputation: 134

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)

Upvotes: 2

Related Questions