sindresorhus / get-windows

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

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

Closed ec2-learn-instant closed 1 month ago

ec2-learn-instant commented 2 months 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 2 months ago

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

trinhxyz commented 2 months 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 2 months ago

Interesting!

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

trinhxyz commented 2 months 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 2 months ago

@sindresorhus - any thoughts on this?

ec2-learn-instant commented 2 months ago

@sindresorhus - How to solve this?

ec2-learn-instant commented 2 months 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 2 months 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 2 months 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.

sindresorhus commented 1 month ago

Please open an issue on electron-forge instead. The problem is not with this package.