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

local modules added with npm can break vite-based build #3624

Open
3 tasks done
noah10 opened this issue Jun 10, 2024 · 1 comment
Open
3 tasks done

local modules added with npm can break vite-based build #3624

noah10 opened this issue Jun 10, 2024 · 1 comment

Comments

@noah10
Copy link

noah10 commented Jun 10, 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.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'

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:

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

...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:

await fs.copy(dep.src, path.resolve(buildPath, dep.dest));
.

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:

packageAfterCopy: async (_config, buildPath) => {
      const symlinkedModules = ['node_modules/logger', 'node_modules/pay-info'];

      const deleteFn = (symlinkMod) => {
        const target = path.join(buildPath, symlinkMod);
        try {
          fs.unlinkSync(target);
          fs.lstatSync(target);
          console.log('logger still exists');
        } catch (err) {
          if (err.code === 'ENOENT') {
            console.log(`${target} has been deleted`)
          } else {
            console.error(err);
          }
        }
      }

      symlinkedModules.forEach(deleteFn)
      
    }

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.

@noah10
Copy link
Author

noah10 commented Jun 20, 2024

It looks like #3632 may be related to this.

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