Skip to content

App entrypoint fails to load for ESM app if arm64 and x64 apps don't match #90

@bendemboski

Description

@bendemboski

If have an app whose main process is implemented as ES modules, and when I add a native dependency and don't merge the ASARs, the app fails to run with:

Uncaught Exception:
Error [ERR_REQUIRE_ESM]: require() of ES Module /private/var/folders/x5/lg2888612qx6k46g8t0b3llm0000gn/T/AppTranslocation/012E8191-C14B-424C-A98A-B6E43D98B159/d/Rowan Patents.app/Contents/Resources/app-arm64.asar/src/index.mjs not supported.
Instead change the require of /private/var/folders/x5/lg2888612qx6k46g8t0b3llm0000gn/T/AppTranslocation/012E8191-C14B-424C-A98A-B6E43D98B159/d/Rowan Patents.app/Contents/Resources/app-arm64.asar/src/index.mjs to a dynamic import() which is available in all CommonJS modules.
at l._load (node:electron/js2c/asar_bundle:2:13642)
at Object.<anonymous> (/private/var/folders/x5/lg2888612qx6k46g8t0b3llm0000gn/T/AppTranslocation/012E8191-C14B-424C-A98A-B6E43D98B159/d/Rowan Patents.app/Contents/Resources/app.asar/index.js:27:1)
at l._load (node:electron/js2c/asar_bundle:2:13642)
at node:electron/js2c/browser_init:2:120247
at node:electron/js2c/browser_init:2:120456
at node:electron/js2c/browser_init:2:120460
at l._load (node:electron/js2c/asar_bundle:2:13642)

I have worked around it using patch-package and replacing has-asar.js with a has-asar.mjs that looks like

import { app } from 'electron';
import path from 'path';

if (process.arch === 'arm64') {
  setPaths('arm64');
} else {
  setPaths('x64');
}

function setPaths(platform) {
  // This should return the full path, ending in something like
  // Notion.app/Contents/Resources/app.asar
  const appPath = app.getAppPath();
  const asarFile = `app-${platform}.asar`;

  // Maybe we'll handle this in Electron one day
  if (path.basename(appPath) === 'app.asar') {
    const platformAppPath = path.join(path.dirname(appPath), asarFile);

    // This is an undocumented API. It exists.
    app.setAppPath(platformAppPath);
  }

  process._archPath = `../${asarFile}`;
}

await import(`${process._archPath}/src/index.mjs`);

However, I'm not sure how to turn this into a general purpose solution because:

  1. I hard-coded the path to my application's entry point (src/index.mjs) and I'm not sure a good way to determine it dynamically.
  2. I'm not sure what process._archPath should actually be in this case?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions