forge
forge copied to clipboard
Error during packaging on macOS
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.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!
Same problem here. Pretty much the vanilla config from the vite typescript template
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)
I am encountering this as well. Usually for
semver/bin/semver.js
orwhich/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).
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
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,
}),
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 https://github.com/electron/forge/issues/3371
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.
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.
Potentially related to this symlink issue https://github.com/electron/asar/pull/308
Fixed (Ref: https://github.com/electron/forge/pull/3592 / https://github.com/electron/asar/pull/308).
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.)
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.)
The problem is caused by @electron/asar, so just update @electron/asar dependency