[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.4.0
Electron version
30.1.0
Operating system
macOS 13.6.3
Last known working Electron Forge version
No response
Expected behavior
When I add a local module (i.e. one that is in another directory in the same repo, rather than hosted in an npm repository) I should be able to use npm run make to successfully build the electron application that I have created from the vite template.
Actual behavior
The application build fails with no error message. It appears to fail on the 'Preparing native dependencies' step (though that's a red herring). Running DEBUG=electron-packager npm run make yields this error message:
An unhandled rejection has occurred inside Forge:
Error: ENOENT: no such file or directory, stat '/private/var/folders/_c/3rpnnjmd0cxb4wkz_k2pyf8c0000gn/T/electron-packager/tmp-J3b8pc/Electron.app/Contents/Resources/app/node_modules/sayhi'
cd electron-forge-symlink-problem/forge-project
npm install
DEBUG=electron-packager npm run make
Additional information
The problem seems to happen when electron-forge copies the dependencies into a temporary directory. When we install the local module, npm creates a symlink for it in the node_modules directory:
ls -ld node_modules/sayhi
lrwxr-xr-x 1 18 Jun 10 11:27 node_modules/sayhi -> ../../common/sayhi
The build process then copies this symlink itself, rather than the directory it points to, into the temp directory:
ls -l /private/var/folders/_c/3rpnnjmd0cxb4wkz_k2pyf8c0000gn/T/electron-packager/tmp-J3b8pc/Electron.app/Contents/Resources/app/node_modules/sayhi
lrwxr-xr-x 1 18 Jun 10 11:52 /private/var/folders/_c/3rpnnjmd0cxb4wkz_k2pyf8c0000gn/T/electron-packager/tmp-J3b8pc/Electron.app/Contents/Resources/app/node_modules/sayhi -> ../../common/sayhi
I think that probably the right fix is for forge (or perhaps packager?) to copy the directory the symlink points to (rather than the symlink itself) into the temporary directory. At that point the vite plugin should no longer have a problem with it.
For anyone else who comes here and needs a temporary solution before the bug is fixed in forge/package/vite plugin, I was able to work around it by adding a packageAfterCopy hook to my forge.config.js that deletes the symlinks from the temp directory and then patching the vite plugin to handle symlinks correctly. If you're able to, I think that using yarn v1 and 'yarn link' (instead of npm) to install your local modules will also work, though I haven't completely tested that yet.
And the patch to VitePlugin is to add {dereference: true} to the copy call from line 125 of the vite plugin (shown above): await fs.copy(dep.src, path.resolve(buildPath, dep.dest), {dereference: true});. This forces the fs-extra.copy call to use lstat rather than stat, causing the vite plugin to copy the directory the symlink points to.
Pre-flight checklist
Electron Forge version
7.4.0
Electron version
30.1.0
Operating system
macOS 13.6.3
Last known working Electron Forge version
No response
Expected behavior
When I add a local module (i.e. one that is in another directory in the same repo, rather than hosted in an npm repository) I should be able to use
npm run make
to successfully build the electron application that I have created from the vite template.Actual behavior
The application build fails with no error message. It appears to fail on the 'Preparing native dependencies' step (though that's a red herring). Running
DEBUG=electron-packager npm run make
yields this error message:Steps to reproduce
You can find a minimal reproduction at https://github.com/noah10/electron-forge-symlink-problem. After checking it out, do the following to reproduce the problem:
Additional information
The problem seems to happen when electron-forge copies the dependencies into a temporary directory. When we install the local module, npm creates a symlink for it in the node_modules directory:
The build process then copies this symlink itself, rather than the directory it points to, into the temp directory:
...but of course the directory that symlink points to does not exist. The ultimate error is triggered when the vite plugin is trying to copy dependencies: https://github.com/electron/forge/blob/38f64e4c9e2c79a3b9ff8447b1a23199415ede97/packages/plugin/vite/src/VitePlugin.ts#L125 .
I think that probably the right fix is for forge (or perhaps packager?) to copy the directory the symlink points to (rather than the symlink itself) into the temporary directory. At that point the vite plugin should no longer have a problem with it.
For anyone else who comes here and needs a temporary solution before the bug is fixed in forge/package/vite plugin, I was able to work around it by adding a packageAfterCopy hook to my forge.config.js that deletes the symlinks from the temp directory and then patching the vite plugin to handle symlinks correctly. If you're able to, I think that using yarn v1 and 'yarn link' (instead of npm) to install your local modules will also work, though I haven't completely tested that yet.
Here's my packageAfterCopy hook:
And the patch to VitePlugin is to add
{dereference: true}
to the copy call from line 125 of the vite plugin (shown above):await fs.copy(dep.src, path.resolve(buildPath, dep.dest), {dereference: true});
. This forces the fs-extra.copy call to use lstat rather than stat, causing the vite plugin to copy the directory the symlink points to.