Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error during packaging on macOS #3549

Closed
3 tasks done
Amstergo opened this issue Mar 25, 2024 · 11 comments
Closed
3 tasks done

Error during packaging on macOS #3549

Amstergo opened this issue Mar 25, 2024 · 11 comments

Comments

@Amstergo
Copy link

Amstergo commented Mar 25, 2024

Pre-flight checklist

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

Electron Forge version

7.3.1

Electron version

29.1.5

Operating system

macOs 13.0.1

Last known working Electron Forge version

No response

Expected behavior

I expect my application to package without errors

Actual behavior

I am encountering an unhandled rejection error while packaging my Electron project using electron-forge package on macOS. The error message is as follows:

❯ Packaging application
› Determining targets...
❯ Packaging for arm64 on darwin
✔ Copying files
⠋ Preparing native dependencies

An unhandled rejection has occurred inside Forge:
Error: Cannot copy '../../../../../loose-envify/cli.js' to a subdirectory of itself, '../../../../../loose-envify/cli.js'.
at /Users/desctop_extension/node_modules/fs-extra/lib/copy/copy.js:213:21
    at FSReqCallback.oncomplete (node:fs:192:23)

The issue only occurs on macOS during the packaging process. However, the project builds and runs successfully on Windows

Steps to reproduce

Additional information

Here are the project dependencies:

"@electron-forge/cli": "^7.3.1",
"@electron-forge/maker-deb": "^7.3.1",
"@electron-forge/maker-dmg": "^7.3.1",
"@electron-forge/maker-pkg": "^7.3.1",
"@electron-forge/maker-rpm": "^7.3.1",
"@electron-forge/maker-squirrel": "^7.3.1",
"@electron-forge/maker-wix": "^7.3.1",
"@electron-forge/maker-zip": "^7.3.1",
"@electron-forge/plugin-auto-unpack-natives": "^7.3.1",
"@electron-forge/plugin-electronegativity": "^7.3.1",
"@electron-forge/plugin-fuses": "^7.3.1",
"@electron-forge/plugin-vite": "^7.3.1",
"@electron/asar": "^3.2.9",
"@electron/fuses": "^1.7.0",

"electron": "29.1.5",

"vite": "^5.2.6",

node -v 18.19.1

file forge.config.ts

import type { ForgeConfig } from '@electron-forge/shared-types'
import MakerSquirrel from '@electron-forge/maker-squirrel'
import MakerZIP from '@electron-forge/maker-zip'
import MakerDmg from '@electron-forge/maker-dmg'
import { VitePlugin } from '@electron-forge/plugin-vite'
import { FusesPlugin } from '@electron-forge/plugin-fuses'
import { FuseV1Options, FuseVersion } from '@electron/fuses'
require('dotenv').config()

const config: ForgeConfig = {
  packagerConfig: {
    asar: true,
    ignore: ['/stats.html', '/.idea', '/.vscode'],
    icon: './assets/images/icons',
    osxSign: {
      identity: process.env.ELECTRON_OSXSIGN_IDENTITY as string,
      // @ts-ignore
      gatekeeperAssess: false,
      platform: 'darwin',
      hardenedRuntime: true,
      entitlements: './entitlements.plist',
      entitlementsInherit: './entitlements.plist',
      signatureFlags: 'library',
    },
    osxNotarize: {
      // @ts-ignore
      tool: 'notarytool',
      teamId: process.env.ELECTRON_NOTARIZE_APP_PROVIDER as string,
      // ascProvider: process.env.ELECTRON_NOTARIZE_APP_PROVIDER as string,
      appleId: process.env.ELECTRON_NOTARIZE_APPLE_ID as string,
      appleIdPassword: process.env.ELECTRON_NOTARIZE_APPLE_PASSWORD as string,
    },
  },
  rebuildConfig: {},
  makers: [
    new MakerSquirrel({
      authors: 'S',
      description: 'S app',
      setupIcon: './assets/images/con.ico',
      loadingGif: './assets/Logo.gif',
      // certificateFile: './convolo.pfx',
      // certificatePassword: process.env.ELECTRON_FORGE_CERTIFICATE_PASSWORD_WINDOWS as string,
    }),
    new MakerZIP({}, ['darwin']),
    new MakerDmg({
      background: './assets/images/logo512x512.png',
      format: 'ULFO',
      debug: true,
    }),
  ],
  publishers: [
    {
      name: '@electron-forge/publisher-electron-release-server',
      config: {
        baseUrl: process.env.ELECTRON_PUBLISHER_BASE_URL as string,
        username: process.env.ELECTRON_PUBLISHER_USER_NAME as string,
        password: process.env.ELECTRON_PUBLISHER_PASSWORD as string,
      },
    },
  ],
  plugins: [
    new VitePlugin({
      build: [
        {
          entry: 'src/main/main.ts',
          config: 'vite.main.config.ts',
        },
        {
          entry: 'src/main/preload.ts',
          config: 'vite.preload.config.ts',
        },
      ],
      renderer: [
        {
          name: 'main_window',
          config: 'vite.renderer.config.ts',
        },
      ],
    }),

    {
      name: '@electron-forge/plugin-auto-unpack-natives',
      config: {},
    },

    {
      name: '@electron-forge/plugin-electronegativity',
      config: {
        isSarif: true,
      },
    },

    new FusesPlugin({
      version: FuseVersion.V1,
      [FuseV1Options.RunAsNode]: false,
      [FuseV1Options.EnableCookieEncryption]: true,
      [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
      [FuseV1Options.EnableNodeCliInspectArguments]: false,
      [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
      [FuseV1Options.OnlyLoadAppFromAsar]: true,
    }),
  ],
}

export default config

file forge.env.d.ts

export {} // Make this a module

declare global {
  // This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Vite
  // plugin that tells the Electron app where to look for the Vite-bundled app code (depending on
  // whether you're running in development or production).
  const MAIN_WINDOW_VITE_DEV_SERVER_URL: string
  const MAIN_WINDOW_VITE_NAME: string

  namespace NodeJS {
    interface Process {
      // Used for hot reload after preload scripts.
      viteDevServers: Record<string, import('vite').ViteDevServer>
    }
  }

  type VitePluginConfig = ConstructorParameters<typeof import('@electron-forge/plugin-vite').VitePlugin>[0]

  interface VitePluginRuntimeKeys {
    VITE_DEV_SERVER_URL: `${string}_VITE_DEV_SERVER_URL`
    VITE_NAME: `${string}_VITE_NAME`
  }
}

declare module 'vite' {
  interface ConfigEnv<K extends keyof VitePluginConfig = keyof VitePluginConfig> {
    root: string
    forgeConfig: VitePluginConfig
    forgeConfigSelf: VitePluginConfig[K][number]
  }
}

file vite.base.config.ts

import { builtinModules } from 'node:module'
import type { AddressInfo } from 'node:net'
import type { ConfigEnv, Plugin, UserConfig } from 'vite'
import pkg from './package.json'

export const builtins = ['electron', ...builtinModules.map((m) => [m, `node:${m}`]).flat()]

export const external = [
  ...builtins,
  ...Object.keys('dependencies' in pkg ? (pkg.dependencies as Record<string, unknown>) : {}),
]

export function getBuildConfig(env: ConfigEnv<'build'>): UserConfig {
  const { root, mode, command } = env

  return {
    root,
    mode,
    build: {
      // Prevent multiple builds from interfering with each other.
      emptyOutDir: false,
      // 🚧 Multiple builds may conflict.
      outDir: '.vite/build',
      watch: command === 'serve' ? {} : null,
      minify: command === 'build',
    },
    clearScreen: false,
  }
}

export function getDefineKeys(names: string[]) {
  const define: { [name: string]: VitePluginRuntimeKeys } = {}

  return names.reduce((acc, name) => {
    const NAME = name.toUpperCase()
    console.log('NAME', NAME)
    const keys: VitePluginRuntimeKeys = {
      VITE_DEV_SERVER_URL: `${NAME}_VITE_DEV_SERVER_URL`,
      VITE_NAME: `${NAME}_VITE_NAME`,
    }

    return { ...acc, [name]: keys }
  }, define)
}

export function getBuildDefine(env: ConfigEnv<'build'>) {
  const { command, forgeConfig } = env
  const names = forgeConfig.renderer.filter(({ name }) => name != null).map(({ name }) => name!)
  const defineKeys = getDefineKeys(names)
  const define = Object.entries(defineKeys).reduce((acc, [name, keys]) => {
    const { VITE_DEV_SERVER_URL, VITE_NAME } = keys
    const def = {
      [VITE_DEV_SERVER_URL]: command === 'serve' ? JSON.stringify(process.env[VITE_DEV_SERVER_URL]) : undefined,
      [VITE_NAME]: JSON.stringify(name),
    }
    return { ...acc, ...def }
  }, {} as Record<string, any>)

  return define
}

export function pluginExposeRenderer(name: string): Plugin {
  const { VITE_DEV_SERVER_URL } = getDefineKeys([name])[name]

  return {
    name: '@electron-forge/plugin-vite:expose-renderer',
    configureServer(server) {
      process.viteDevServers ??= {}
      // Expose server for preload scripts hot reload.
      process.viteDevServers[name] = server

      server.httpServer?.once('listening', () => {
        const addressInfo = server.httpServer!.address() as AddressInfo
        // Expose env constant for main process use.
        process.env[VITE_DEV_SERVER_URL] = `http://localhost:${addressInfo?.port}`
      })
    },
  }
}

export function pluginHotRestart(command: 'reload' | 'restart'): Plugin {
  return {
    name: '@electron-forge/plugin-vite:hot-restart',
    closeBundle() {
      if (command === 'reload') {
        for (const server of Object.values(process.viteDevServers)) {
          // Preload scripts hot reload.
          server.ws.send({ type: 'full-reload' })
        }
      } else {
        // Main process hot restart.
        // https://github.com/electron/forge/blob/v7.2.0/packages/api/core/src/api/start.ts#L216-L223
        process.stdin.emit('data', 'rs')
      }
    },
  }
}

file vite.main.config.ts

import type { ConfigEnv, UserConfig } from 'vite'
import { defineConfig, mergeConfig } from 'vite'
import { getBuildConfig, getBuildDefine, external, pluginHotRestart } from './vite.base.config'

export default defineConfig((env) => {
  const forgeEnv = env as ConfigEnv<'build'>
  const { forgeConfigSelf } = forgeEnv
  const define = getBuildDefine(forgeEnv)
  const config: UserConfig = {
    build: {
      lib: {
        entry: forgeConfigSelf.entry!,
        fileName: () => '[name].js',
        formats: ['cjs'],
      },
      rollupOptions: {
        external,
      },
    },
    plugins: [pluginHotRestart('restart')],
    define,
    resolve: {
      // Load the Node.js entry.
      // browserField: false,
      mainFields: ['module', 'jsnext:main', 'jsnext'],
    },
  }

  return mergeConfig(getBuildConfig(forgeEnv), config)
})

vite.preload.config.ts

import type { ConfigEnv, UserConfig } from 'vite'
import { defineConfig, mergeConfig } from 'vite'
import { getBuildConfig, external, pluginHotRestart } from './vite.base.config'

// https://vitejs.dev/config
export default defineConfig((env) => {
  const forgeEnv = env as ConfigEnv<'build'>
  const { forgeConfigSelf } = forgeEnv
  const config: UserConfig = {
    build: {
      rollupOptions: {
        external,
        // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`.
        input: forgeConfigSelf.entry!,
        output: {
          format: 'cjs',
          // It should not be split chunks.
          inlineDynamicImports: true,
          entryFileNames: '[name].js',
          chunkFileNames: '[name].js',
          assetFileNames: '[name].[ext]',
        },
      },
    },
    plugins: [pluginHotRestart('reload')],
  }

  return mergeConfig(getBuildConfig(forgeEnv), config)
})

file vite.renderer.config.ts

import type { ConfigEnv, UserConfig } from 'vite'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import svgr from 'vite-plugin-svgr'
import { visualizer } from 'rollup-plugin-visualizer'
import { pluginExposeRenderer } from './vite.base.config'

export default defineConfig((env) => {
  const forgeEnv = env as ConfigEnv<'renderer'>
  const { root, mode, forgeConfigSelf } = forgeEnv
  const name = forgeConfigSelf.name ?? ''

  return {
    root,
    mode,
    base: './',
    build: {
      outDir: `.vite/renderer/${name}`,
    },
    plugins: [
      pluginExposeRenderer(name),
      visualizer(),
      react(),
      svgr({
        svgrOptions: {},
        include: '**/*.svg',
      }),
    ],
    optimizeDeps: {
      include: ['@emotion/styled'],
    },
    resolve: {
      preserveSymlinks: true,
    },
    clearScreen: false,
  } as UserConfig
})

Please help me resolve this issue or provide guidance on how to further debug the problem. Thank you!

@DennisKo
Copy link

Same problem here. Pretty much the vanilla config from the vite typescript template

@antoniaelsen
Copy link

I am encountering this as well. Usually for semver/bin/semver.js or which/bin/which. I have the same error as OP when I use yarn as a package manager, with npm it's different but fails on the same package:

An unhandled rejection has occurred inside Forge:
Error: /var/folders/1d/nq17plrd0psgslq4n1n5gy_40000gn/T/electron-packager/tmp-MQcYl5/Electron.app/Contents/Resources/app/node_modules/@electron/get/node_modules/.bin/semver: file "../../../../../../../../../../../../var/folders/1d/nq17plrd0psgslq4n1n5gy_40000gn/T/electron-packager/tmp-MQcYl5/Electron.app/Contents/Resources/app/node_modules/@electron/get/node_modules/semver/bin/semver.js" links out of the package
at Filesystem.insertLink (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/filesystem.js:106:13)
    at handleFile (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/asar.js:132:20)
    at next (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/asar.js:148:11)
    at next (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/asar.js:149:12)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async MacApp.asarApp (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/platform.ts:245:5)
    at async MacApp.buildApp (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/platform.ts:150:5)
    at async MacApp.initialize (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/platform.ts:141:7)
    at async MacApp.create (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/mac.ts:435:5)
    at async Promise.all (index 0)
    at async packager (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/packager.ts:246:20)

@solidSpoon
Copy link

I am encountering this as well. Usually for semver/bin/semver.js or which/bin/which. I have the same error as OP when I use yarn as a package manager, with npm it's different but fails on the same package:

An unhandled rejection has occurred inside Forge:
Error: /var/folders/1d/nq17plrd0psgslq4n1n5gy_40000gn/T/electron-packager/tmp-MQcYl5/Electron.app/Contents/Resources/app/node_modules/@electron/get/node_modules/.bin/semver: file "../../../../../../../../../../../../var/folders/1d/nq17plrd0psgslq4n1n5gy_40000gn/T/electron-packager/tmp-MQcYl5/Electron.app/Contents/Resources/app/node_modules/@electron/get/node_modules/semver/bin/semver.js" links out of the package
at Filesystem.insertLink (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/filesystem.js:106:13)
    at handleFile (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/asar.js:132:20)
    at next (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/asar.js:148:11)
    at next (/Users/antonia/projects/other/my-app/node_modules/@electron/asar/lib/asar.js:149:12)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async MacApp.asarApp (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/platform.ts:245:5)
    at async MacApp.buildApp (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/platform.ts:150:5)
    at async MacApp.initialize (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/platform.ts:141:7)
    at async MacApp.create (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/mac.ts:435:5)
    at async Promise.all (index 0)
    at async packager (/Users/antonia/projects/other/my-app/node_modules/@electron/packager/src/packager.ts:246:20)

Encountered the same issue here. I'm using a pretty standard configuration from the Vite TypeScript template. The problem arose when I added the dependency "@electron-forge/publisher-github": "^7.3.1". I'm running on macOS 14.1.2 (23B92).

@jgresham
Copy link

jgresham commented Apr 6, 2024

Same, using npm as my package installer

An unhandled rejection has occurred inside Forge:
Error: 
/var/folders/ck/jkwcs10946xf1cgp754gh96m0000gn/T/electron-packager/tmp-ONUw7C/Electron.app/Contents/Resources/app/node_modules/conf/node_modules/.bin/semver: 
file 
"../../../../../../../../../../../../var/folders/ck/jkwcs10946xf1cgp754gh96m0000gn/T/electron-packager/tmp-ONUw7C/Electron.app/Contents/Resources/app/node_modules/conf/node_modules/semver/bin/semver.js"
links out of the package

@solidSpoon
Copy link

This just work for me, but i don`t know why.

const config: ForgeConfig = {
    packagerConfig: {
-       asar: true,
+       asar: false,
        icon: './assets/icons/icon',
        extraResource: ["./drizzle"],
        executableName: 'dash-player',
        name: 'DashPlayer',
    },
.....
        // Fuses are used to enable/disable various Electron functionality
        // at package time, before code signing the application
        new FusesPlugin({
            version: FuseVersion.V1,
            [FuseV1Options.RunAsNode]: false,
            [FuseV1Options.EnableCookieEncryption]: true,
            [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
-           [FuseV1Options.EnableNodeCliInspectArguments]: false,
+           [FuseV1Options.EnableNodeCliInspectArguments]: true,
            [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
-           [FuseV1Options.OnlyLoadAppFromAsar]: true,
+           [FuseV1Options.OnlyLoadAppFromAsar]: false,
        }),

@jgresham
Copy link

jgresham commented Apr 8, 2024

This just work for me, but i don`t know why.

const config: ForgeConfig = {
    packagerConfig: {
-       asar: true,
+       asar: false,
        icon: './assets/icons/icon',
        extraResource: ["./drizzle"],
        executableName: 'dash-player',
        name: 'DashPlayer',
    },
.....
        // Fuses are used to enable/disable various Electron functionality
        // at package time, before code signing the application
        new FusesPlugin({
            version: FuseVersion.V1,
            [FuseV1Options.RunAsNode]: false,
            [FuseV1Options.EnableCookieEncryption]: true,
            [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
-           [FuseV1Options.EnableNodeCliInspectArguments]: false,
+           [FuseV1Options.EnableNodeCliInspectArguments]: true,
            [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
-           [FuseV1Options.OnlyLoadAppFromAsar]: true,
+           [FuseV1Options.OnlyLoadAppFromAsar]: false,
        }),

A decent interim solution, but its not preferable to disable asar https://www.electronjs.org/docs/latest/tutorial/asar-archives.

Also, unfortunately disabling asar leads to another error for me #3371

@jgresham
Copy link

jgresham commented Apr 9, 2024

I converted my repo from electron-builder to electron-forge and somewhere along the way npm or node_modules cache was stuck. Cloning my repo in a new directory and fresh npm install fixed this issue.

@sethyuan
Copy link

sethyuan commented Apr 16, 2024

I too ran into the same issue, and after some investigation, I found that the files to be packaged into asar cannot have soft links because the path resolving algorithm is buggy.

@erickzhao
Copy link
Member

Potentially related to this symlink issue electron/asar#308

@BlackHole1
Copy link
Member

Fixed (Ref: #3592 / electron/asar#308).

@noah10
Copy link

noah10 commented Jun 6, 2024

Sorry to comment on a closed issue, but I'm hoping someone might be able to tell me (a) when this might be released or (b) how I can use it before it's released. (I've tried checking out electron/forge main and yarn linking to it as described in the "Running Forge Locally" section of "Contributing" and replacing electron-forge in package.json with my local version (which I'd prefer to avoid), but the problem persisted in both cases.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants