forge icon indicating copy to clipboard operation
forge copied to clipboard

Webpack plugin errors when using universal native node modules on macOS

Open tofumatt opened this issue 1 year ago • 7 comments

Pre-flight checklist

  • [X] I have read the contribution documentation for this project.
  • [X] I agree to follow the code of conduct that this project uses.
  • [X] I have searched the issue tracker for a bug that matches the one I want to file, without success.

Electron Forge version

7.3.0

Electron version

27.3.5

Operating system

macOS 14.3.1 (23D60)

Last known working Electron Forge version

7.2.0

Expected behavior

A universal (arm64 and x86) native node module should not cause the error:

An unhandled rejection has occurred inside Forge:
Error: Could not find originating native module for "main/native_modules/build/Release/nsUbiquitousKeyValueStore.node"
at Task.task (/Users/matt/Projects/turnip-timer/node_modules/@electron-forge/plugin-webpack/src/WebpackPlugin.ts:211:33)

I suspect this is related to the "magic native module mapping" done in #3437.

Actual behavior

The webpack build should not error when a native node module that is a universal binary is used.

Steps to reproduce

I don't have good steps to reproduce because it's a private repo, but using node-mac-icloud-keyvalue as a node dependency (which is publicly available) is what triggers the issue, since it's built as a universal binary.

Using electron forge 7.2.0 does not exhibit the issue.

Additional information

Relevant parts of my forge.config.ts look like this:

const config: ForgeConfig = {
  makers: [new MakerPKG({})],
  packagerConfig: {
    // App metadata trimmed for readability, but this part is probably relevant:
    osxUniversal: {
      x64ArchFiles: 'Contents/Resources/app/.webpack/**/*.node',
    },
  },
  plugins: [
    new WebpackPlugin({
      devContentSecurityPolicy: `default-src * self blob: data: gap:; style-src * self 'unsafe-inline' blob: data: gap:; script-src * 'self' 'unsafe-eval' 'unsafe-inline' blob: data: gap:; object-src * 'self' blob: data: gap:; img-src * self 'unsafe-inline' blob: data: gap:; connect-src self * 'unsafe-inline' blob: data: gap:; frame-src * self blob: data: gap:;`,
      devServer: {
        // Disable error overlays; we use our own Error boundaries.
        client: {
          overlay: {
            errors: false,
            runtimeErrors: false,
            warnings: false,
          },
        },
        // Disable dev server live reload so React Refresh works.
        liveReload: false,
      },
      // Config includes recommended use of `@vercel/webpack-asset-relocator-loader` from https://www.electronforge.io/config/plugins/webpack#native-node-modules
      mainConfig,
      renderer: {
        config: rendererConfig,
        entryPoints: [
          {
            html: './src/renderer/index.html',
            js: `./src/renderer/entryPoint.ts`,
            name: 'react_app',
            nodeIntegration: true,
            preload: {
              config: preloadConfig,
              js: './src/preload/index.ts',
            },
          },
        ],
        nodeIntegration: true,
      },
    }),
  ],
  rebuildConfig: {},
};

export default config;

tofumatt avatar Mar 08 '24 21:03 tofumatt

Seeing the same issue on Electron Forge 7.4.0. Downgrading to 7.2.0 fixes it.

nikwen avatar May 29 '24 04:05 nikwen

Treat this as a FYI comment.

Also seeing this when the native library resides in a hidden directory, e.g.

ls -t node_modules/level.lib-native-macos/.build/*.node
node_modules/level.lib-native-macos/.build/LevelNativeApi.node

This is due to fast-glob not including hidden directories/files when globbing (see here) which is used by WebpackPlugin.ts#L192.

I don't think this should be fixed though as published native libs in a hidden dir would typically not exist in the wild. In my case it was with my own native library build which was easily fixed by changing the build output dir.

instilled avatar Jun 05 '24 17:06 instilled

@instilled Thanks for the comment about the hidden directory!

I use an npm package that expects a native library to be at a certain path relative to the JavaScript bundle. The Forge WebPack plugin places JavaScript bundles into a hidden directory .webpack. So the native library needs to be in that hidden directory as well.

Hence, I think this should be fixed.

nikwen avatar Jul 05 '24 15:07 nikwen

Update: Here's what caused the error in my case:

I had a script to build a universal macOS .node binary for one of my dependencies. Then I would use Webpack's CopyPlugin to copy it into my Webpack output directory.

It seems like Forge v7.3.0 introduced the ability to build universal macOS binaries with native dependencies without the need for an external build script. This broke my existing configuration.

Removing the CopyPlugin from the renderer config and letting Forge build the universal .node binary itself solved my issues.

nikwen avatar Sep 12 '24 21:09 nikwen

Related issue that has a PR: #3792

nikwen avatar Dec 27 '24 13:12 nikwen

Somewhat surprised this isn't a higher priority to fix, as far as I can tell it blocks using native node modules + universal builds together, which must be an incredibly common combination. Are there workarounds folks are using? I have migrated to electron-builder for now.

davidgoli avatar Sep 24 '25 16:09 davidgoli