{"id":15628414,"url":"https://github.com/itsmapleleaf/remix-electron","last_synced_at":"2025-09-28T10:30:33.244Z","repository":{"id":43401222,"uuid":"451665023","full_name":"itsMapleLeaf/remix-electron","owner":"itsMapleLeaf","description":"Electron integration for Remix ⚛💿","archived":false,"fork":false,"pushed_at":"2024-09-04T17:32:11.000Z","size":1968,"stargazers_count":303,"open_issues_count":4,"forks_count":20,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-01-11T11:06:13.556Z","etag":null,"topics":["electron","javascript","js","react","remix"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itsMapleLeaf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-24T23:12:36.000Z","updated_at":"2025-01-10T06:47:21.000Z","dependencies_parsed_at":"2023-12-19T07:55:52.388Z","dependency_job_id":"791a602a-8c77-48c4-bcf2-8d73b2f6086b","html_url":"https://github.com/itsMapleLeaf/remix-electron","commit_stats":{"total_commits":309,"total_committers":6,"mean_commits":51.5,"dds":0.04854368932038833,"last_synced_commit":"1ba118a093c9c3a64253c3e056fbfe62e50ba8aa"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsMapleLeaf%2Fremix-electron","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsMapleLeaf%2Fremix-electron/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsMapleLeaf%2Fremix-electron/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsMapleLeaf%2Fremix-electron/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itsMapleLeaf","download_url":"https://codeload.github.com/itsMapleLeaf/remix-electron/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234505106,"owners_count":18843674,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["electron","javascript","js","react","remix"],"created_at":"2024-10-03T10:22:30.240Z","updated_at":"2025-09-28T10:30:32.887Z","avatar_url":"https://github.com/itsMapleLeaf.png","language":"TypeScript","readme":"# remix-electron\n\nElectron integration for Remix\n\n![demo screenshot](./screenshot.png)\n\n## Setup\n\nUse degit to create a new project from the template.\n\n```sh\nnpx degit itsMapleLeaf/remix-electron/workspaces/template my-desktop-app\n```\n\n### Adding to an existing Remix project\n\nInstall remix-electron and electron:\n\n```bash\nnpm i remix-electron electron\n```\n\nAdd a file at `desktop/index.js` to run the electron app. The `initRemix` function returns a url to load in the browser window.\n\n```ts\n// desktop/index.js\nconst { initRemix } = require(\"remix-electron\")\nconst { app, BrowserWindow } = require(\"electron\")\nconst { join } = require(\"node:path\")\n\n/** @type {BrowserWindow | undefined} */\nlet win\n\napp.on(\"ready\", async () =\u003e {\n\ttry {\n\t\tconst url = await initRemix({\n\t\t\tserverBuild: join(process.cwd(), \"build/index.js\"),\n\t\t})\n\n\t\twin = new BrowserWindow({ show: false })\n\t\tawait win.loadURL(url)\n\t\twin.show()\n\t} catch (error) {\n\t\tconsole.error(error)\n\t}\n})\n```\n\nBuild the app with `npm run build`, then run `npx electron desktop/index.js` to start the app! 🚀\n\n## Using Electron APIs\n\nImporting `\"electron\"` directly in route files results in Electron trying to get bundled and called in the browser / renderer process.\n\nTo circumvent this, create a `electron.server.ts` file, which re-exports from electron. The `.server` suffix tells Remix to only load it in the main process. You should use `.server` for any code that runs in the main process and uses node/electron APIs.\n\n```ts\n// app/electron.server.ts\nimport electron from \"electron\"\nexport default electron\n```\n\n```ts\n// app/routes/_index.tsx\nimport electron from \"~/electron.server\"\n\nexport function loader() {\n\treturn {\n\t\tuserDataPath: electron.app.getPath(\"userData\"),\n\t}\n}\n```\n\nLikewise, for any code running in the renderer process, e.g. using the [clipboard](https://www.electronjs.org/docs/latest/api/clipboard) module, you can use the `.client` suffix. Renderer process modules require `nodeIntegration`.\n\n```ts\n// desktop/index.js\nfunction createWindow() {\n\t// ...\n\twin = new BrowserWindow({\n\t\t// ...\n\t\twebPreferences: {\n\t\t\tnodeIntegration: true,\n\t\t},\n\t})\n}\n```\n\n## API\n\n### `async initRemix({ serverBuild[, publicFolder, mode, getLoadContext] })`\n\nInitializes remix-electron. Returns a promise with a url to load in the browser window.\n\nOptions:\n\n- `serverBuild`: The path to your server build (e.g. `path.join(process.cwd(), 'build')`), or the server build itself (e.g. required from `@remix-run/dev/server-build`). Updates on refresh are only supported when passing a path string.\n\n- `mode`: The mode the app is running in. Can be `\"development\"` or `\"production\"`. Defaults to `\"production\"` when packaged, otherwise uses `process.env.NODE_ENV`.\n\n- `publicFolder`: The folder where static assets are served from, including your browser build. Defaults to `\"public\"`. Non-absolute paths are resolved relative to `process.cwd()`.\n\n- `getLoadContext`: Use this to inject some value into all of your remix loaders, e.g. an API client. The loaders receive it as `context`.\n\n- `esm`: Set this to `true` to use remix-electron in an ESM application.\n\n\u003cdetails\u003e\n\u003csummary\u003eLoad context TS example\u003c/summary\u003e\n\n**app/context.ts**\n\n```ts\nimport type * as remix from \"@remix-run/node\"\n\n// your context type\nexport type LoadContext = {\n\tsecret: string\n}\n\n// a custom data function args type to use for loaders/actions\nexport type DataFunctionArgs = Omit\u003cremix.DataFunctionArgs, \"context\"\u003e \u0026 {\n\tcontext: LoadContext\n}\n```\n\n**desktop/main.js**\n\n```ts\nconst url = await initRemix({\n\t// ...\n\n\t/** @type {import(\"~/context\").LoadContext} */\n\tgetLoadContext: () =\u003e ({\n\t\tsecret: \"123\",\n\t}),\n})\n```\n\nIn a route file:\n\n```ts\nimport type { DataFunctionArgs, LoadContext } from \"~/context\"\n\nexport async function loader({ context }: DataFunctionArgs) {\n\t// do something with context\n}\n```\n\n\u003c/details\u003e\n\n## Motivation\n\nElectron has [a comprehensive list of security recommendations](https://www.electronjs.org/docs/latest/tutorial/security) to follow when building an app, especially if that app interacts with the web. Which includes, but is not limited to:\n\n- Using `preload.js` files to expose specific electron functionality to your app, via globals\n- Using IPC communication\n- Avoiding `remote.require` (which has since been removed)\n\nThese practices can lead to a lot of awkward boilerplate and splitting up related code across multiple files and domains.\n\nWith `remix-electron`, you can freely use Electron APIs in Remix loader functions. It's a Node process with full Node capabilities, with access to the full Electron API, none of which runs in the browser.\n\nThe browser only receives data and renders a view. Additionally, you can neatly colocate your main process code right beside the related renderer code in a route file.\n\nThinking about it another way: it's like a normal Remix web app, except Electron is your backend.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsmapleleaf%2Fremix-electron","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitsmapleleaf%2Fremix-electron","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsmapleleaf%2Fremix-electron/lists"}