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

feat: electron desktop app without express server #1136

Open
wants to merge 34 commits into
base: main
Choose a base branch
from

Conversation

Derek-X-Wang
Copy link

@Derek-X-Wang Derek-X-Wang commented Jan 20, 2025

Motivation

Turning bolt.diy into a desktop application will make it easier for non-technical users to access. It also opens up the potential for accessing system-level APIs.

I have seen the awesome PR by @thecodacus, and I still want to share my approach with the bolt.diy community because it takes a different path:

  • No Express server: I load the Remix bundle directly in the Electron main process. Remix loaders and actions can freely use Electron APIs.
  • No changes in the app folder: This approach keeps maintenance simple by isolating Electron-specific changes to an electron folder.
  • Persists the API key entered by the user.

Scope

  • Integrate Electron packaging for the existing Remix bundle.
  • Run the Remix server bundle directly within the Electron main process.
  • Persist window size and API key using ElectronStore.

Limitation

  • Currently, I have only tested this on a Mac environment.
  • Packager and auto-update features are not done yet.

Related

For reference to the existing Electron approach, see this PR.

Screenshot 2025-01-20 at 12 05 47 AM

@thecodacus
Copy link
Collaborator

hey this looks awesome.
I was really not sure how to host the server in electron except the remix adaptors that comes with it.
you actually went more low level to run the server 👍

but not sure if this will require more maintenance or less looks like there are quite a lot of stuff you are ding to handle http request and passing to node adaptor

@leex279 leex279 self-requested a review January 20, 2025 09:50
@Derek-X-Wang
Copy link
Author

yeah, it might need more tweaks for handling http because, in this setup, you’re not actually sending requests to an http server but instead to the main thread. that’s why i added cookie forwarding to persist the api key. i intercept the request and set it in a cookie.

      // Forward cookies to remix server
      const cookies = await session.defaultSession.cookies.get({ name: 'apiKeys' });

      if (cookies.length > 0) {
        req.headers.set('Cookie', cookies.map((c) => `${c.name}=${c.value}`).join('; '));
        store.set('apiKeys', cookies[0].value);
      }

the benefit of this approach is that you can directly use electron apis in remix server loaders and actions. this opens up a lot of potential for adding features to the desktop app.

i call it easy to maintain because it makes adopting upstream changes much simpler. it keeps the web app separate from the electron app. the electron app essentially just utilizes the remix server bundle without requiring any additional changes. as you see, no changes to the app folder.

@thecodacus
Copy link
Collaborator

yeah, it might need more tweaks for handling http because, in this setup, you’re not actually sending requests to an http server but instead to the main thread. that’s why i added cookie forwarding to persist the api key. i intercept the request and set it in a cookie.

      // Forward cookies to remix server
      const cookies = await session.defaultSession.cookies.get({ name: 'apiKeys' });

      if (cookies.length > 0) {
        req.headers.set('Cookie', cookies.map((c) => `${c.name}=${c.value}`).join('; '));
        store.set('apiKeys', cookies[0].value);
      }

yeah I love it. its exactly what I thought you are doing. I think this is better approach as its not opening a new port in the os.
i was thinking how can i stop spawning a server on a port myself. cuz if i open 2 instance there will be port conflict

i call it easy to maintain because it makes adopting upstream changes much simpler. it keeps the web app separate from the electron app. the electron app essentially just utilizes the remix server bundle without requiring any additional changes. as you see, no changes to the app folder.

yeah I agree, even the express approach is not changing anything thats specific to electron. that PR is just de-cloudflaring it cuz we want to add ability to host other platforms like netlify and vercel.

by "more maintanance" what i meant was, the index.ts is too big and not very organized. I would suggest if you can refactor this index.ts code into more readable smaller modules so that will be easy to maintain.

also you have forwarded the cookies for apikeys. why its a separately implemented effort? the best solution would be not having any specific code for that (just pass what ever cookies are received).

for example: it does not have other cookies that were used like providerSettings.
it would be an extra burden to maintain this file everytime we add new cookie parameters
So I would love to see am improvement on this which just forward all the cookies that are present in the request without having a special implementation steps

@Derek-X-Wang
Copy link
Author

yeah I agree, even the express approach is not changing anything thats specific to electron. that PR is just de-cloudflaring it cuz we want to add ability to host other platforms like netlify and vercel.

Oh, yup. in that case, it's totally make sense to replace @remix-run/cloudflare with @remix-run/server-runtime

by "more maintanance" what i meant was, the index.ts is too big and not very organized. I would suggest if you can refactor this index.ts code into more readable smaller modules so that will be easy to maintain.

Sure. that's easy. I will update it.

also you have forwarded the cookies for apikeys. why its a separately implemented effort? the best solution would be not having any specific code for that (just pass what ever cookies are received).
for example: it does not have other cookies that were used like providerSettings.
it would be an extra burden to maintain this file everytime we add new cookie parameters
So I would love to see am improvement on this which just forward all the cookies that are present in the request without having a special implementation steps

Good question. I think I was trying to persist the apiKeys when I added that logic. but I was not sure if I shall persist other cookies. maybe I just store all cookies so all settings will remain the same. will update

@Derek-X-Wang
Copy link
Author

Hi @thecodacus,
I refactor the index.ts file into couple smaller modules.
and store all cookies, not just apiKeys

@leex279 leex279 added the WIP Work In Progress label Jan 28, 2025
@thecodacus
Copy link
Collaborator

is it ready.. I still see it in draft state

@Derek-X-Wang
Copy link
Author

ah, i didn’t know you were waiting for that.

right now, i’m able to run the unpacked version (electron:build:unpack) on my mac without any issues. but as i understand it, we want to prepare distributions for windows, mac, and linux.

i haven’t tested the packaged version yet, and that’s what i’ll do next. i can test it on mac and windows.

once i confirm the packaged version works on mac and windows, i’ll mark this pr as ready for review. i’ve been less busy lately, so i should be able to wrap it up soon.

@leex279 leex279 mentioned this pull request Jan 31, 2025
@Derek-X-Wang
Copy link
Author

@thecodacus
I was able to test
zip, dmg builds on mac
zip, exe builds on windows
work fine.
I will resolve the merge conflicts.

@Derek-X-Wang Derek-X-Wang marked this pull request as ready for review February 2, 2025 08:51
@Derek-X-Wang
Copy link
Author

merge conflicts resolved

@thecodacus
Copy link
Collaborator

@Derek-X-Wang, I am getting this error on mac build
image

@Derek-X-Wang
Copy link
Author

this is due to the server build not loading correctly, usually caused by path resolution issues.
which app version are you running?
unpacked version (electron:build:unpack)
dist version - zip(electron:build:mac)
dist version - dmg(electron:build:mac)

@thecodacus
Copy link
Collaborator

thecodacus commented Feb 11, 2025

this is due to the server build not loading correctly, usually caused by path resolution issues. which app version are you running? unpacked version (electron:build:unpack) dist version - zip(electron:build:mac) dist version - dmg(electron:build:mac)

dmg

usually the dist builds are what we should be publishing as release. as that comes with an installer

@Derek-X-Wang
Copy link
Author

I installed the dmg I built from my side. Cannot reproduce this issue.
could you send me the log file at ~/Library/Logs/bolt/main.log?

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

Successfully merging this pull request may close these issues.

3 participants