sindresorhus / get-windows

Get metadata about the active window and open windows (title, id, bounds, owner, etc)
MIT License
793 stars 162 forks source link

Electron Forge resolving path to node module using absolute path rather than using relative path #189

Open ec2-learn-instant opened 1 week ago

ec2-learn-instant commented 1 week ago

I'm trying to create an app that include the get-windows npm package, but I cannot distribute my app because Electron Forge is using resolving the package to an absolute path rather than a relative path, so the app fails to find the package.

[error] (node:13140) UnhandledPromiseRejectionWarning: Error: D:\VMKV\electron-app\node_modules\get-windows\package.jsondoes not exist at t.find (C:\Users\Quick App Studio\AppData\Local\Programs\my-electron-app\resources\app.asar.webpack\main\index.js:2:3391) at p (C:\Users\Quick App Studio\AppData\Local\Programs\my-electron-app\resources\app.asar.webpack\main\index.js:2:1654721) at m (C:\Users\Quick App Studio\AppData\Local\Programs\my-electron-app\resources\app.asar.webpack\main\index.js:2:1654862) at Module.n (C:\Users\Quick App Studio\AppData\Local\Programs\my-electron-app\resources\app.asar.webpack\main\index.js:2:1649771) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async App. (C:\Users\Quick App Studio\AppData\Local\Programs\my-electron-app\resources\app.asar.webpack\main\index.js:2:13148557)

Also note, I am using the following versions:

Node: 20.16.0 Electron: ^30.0.2 electron-forge/cli: ^7.4.0 get-windows: ^9.2.0

Please let me know if there's any missing info.

Nantris commented 5 days ago

This seems like an electron-forge issue, not an issue with this package. Am I wrong?

trinhxyz commented 5 days ago

@Nantris - I ran into this issue as well, I'm pretty sure its caused by this code in macos.js:

// I'm pretty sure this code creates an absolute path 
const __dirname = path.dirname(fileURLToPath(import.meta.url));

const execFile = promisify(childProcess.execFile);
const binary = path.join(__dirname, '../main');
Nantris commented 5 days ago

Interesting!

Link to the relevant code for convenience: https://github.com/sindresorhus/get-windows/blob/6e84e52e43469e2836f5b11e9de5d239a9963b54/lib/macos.js#L6-L9

trinhxyz commented 5 days ago

@Nantris - just for more context, I ran into this issue because the version of my Electron app packaged from GH Actions was complaining about a missing file in C:\Github\Runner\..., and locally packaged versions of my Electron app wouldn't run on other machines because of a similar error, ENOENT, and searching for a file in C:\Users\trinhxyz\....

trinhxyz commented 4 days ago

@sindresorhus - any thoughts on this?

ec2-learn-instant commented 4 days ago

@sindresorhus - How to solve this?

ec2-learn-instant commented 4 days ago

Hi @sindresorhus, after too many hours of spending my time, finally I solved this issue by using the process.resourcePath .

Here is my code for production as well as development for Electron Forge Webpack - windows.js file

import path from 'node:path';
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';
import { createRequire } from 'node:module';
import preGyp from '@mapbox/node-pre-gyp';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const getAddon = () => {
        const require = createRequire(import.meta.url);
    const isProduction = process.env.NODE_ENV === 'production';
    if (isProduction) {
        const packageJsonPath = path.join(process.resourcesPath, "app.asar\\.webpack\\main\\node_modules\\get-windows\\package.json");
        const bindingPath = preGyp.find(packageJsonPath);
        return (fs.existsSync(bindingPath)) ? require(bindingPath) : {
            getActiveWindow() { },
            getOpenWindows() { },
        }; 
         } else {
        const bindingPath = preGyp.find(path.resolve(path.join(__dirname, '../package.json')));
        return (fs.existsSync(bindingPath)) ? require(bindingPath) : {
            getActiveWindow() { },
            getOpenWindows() { },
        };
    }
};

export async function activeWindow() {
    return getAddon().getActiveWindow();
}

export function activeWindowSync() {
    return getAddon().getActiveWindow();
}

export function openWindows() {
    return getAddon().getOpenWindows();
}

export function openWindowsSync() {
    return getAddon().getOpenWindows();
}

@Nantris @trinhxyz @jyboudreau Please take a look.

trinhxyz commented 4 days ago

@ec2-learn-instant - this looks like an okay work around, but IMO this shouldn't be needed and the package should just work out of the box

Nantris commented 4 days ago

For what it's worth, we do not use electron-forge and it does just work out of the box (I tested on mac/win/linux + dev/prod for each)

Still, if this can be resolved for electron-forge I think it should be and I'm sure a well explained and tested PR would be accepted.