• Stars
    star
    283
  • Rank 146,066 (Top 3 %)
  • Language
    TypeScript
  • Created almost 3 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Electron integration for Remix βš›πŸ’Ώ

remix-electron

Electron integration for Remix

demo screenshot

Setup

Use degit to create a new project from the template.

npx degit itsMapleLeaf/remix-electron/template my-desktop-app

Adding to an existing Remix project

Install remix-electron and peer dependencies:

npm i remix-electron electron @remix-run/node @remix-run/server-runtime react react-dom

Add a file at desktop/main.js to run the electron app. The initRemix function returns a url to load in the browser window.

// desktop/main.js
const { initRemix } = require("remix-electron")
const { app, BrowserWindow } = require("electron")
const { join } = require("node:path")

let win

app.on("ready", async () => {
  try {
    const url = await initRemix({
      serverBuild: join(__dirname, "build"),
    })

    win = new BrowserWindow({ show: false })
    await win.loadURL(url)
    win.show()
  } catch (error) {
    console.error(error)
  }
})

Update serverBuildPath in your Remix config:

// remix.config.js
/**
 * @type {import('@remix-run/dev/config').AppConfig}
 */
module.exports = {
  serverBuildPath: "desktop/build/index.js",
  // ...
}

Build the app with npm run build, then run npx electron desktop/main.js to start the app! πŸš€

Using Electron APIs

Importing "electron" directly in route files results in Electron trying to get bundled and called in the browser / renderer process.

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

// app/electron.server.ts
// @ts-nocheck
import electron from "electron"
export = electron

Likewise, for any code running in the renderer process, e.g. using the clipboard module, you can use the .client suffix. Renderer process modules require nodeIntegration.

// desktop/main.ts
function createWindow() {
  // ...
  win = new BrowserWindow({
    // ...
    webPreferences: {
      nodeIntegration: true,
    },
  })
}

API

async initRemix({ serverBuild[, publicFolder, mode, getLoadContext] })

Initializes remix-electron. Returns a promise with a url to load in the browser window.

Options:

  • serverBuild: The path to your server build (e.g. path.join(__dirname, '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.

  • mode: The mode the app is running in. Can be "development" or "production". Defaults to "production" when packaged, otherwise uses process.env.NODE_ENV.

  • publicFolder: The folder where static assets are served from, including your browser build. Defaults to "public". Non-relative paths are resolved relative to app.getAppPath().

  • getLoadContext: Use this to inject some value into all of your remix loaders, e.g. an API client. The loaders receive it as context

Load context TS example

app/context.ts

import type * as remix from "@remix-run/server-runtime"

// your context type
export type LoadContext = {
  secret: string
}

// a custom data function args type to use for loaders/actions
export type DataFunctionArgs = Omit<remix.DataFunctionArgs, "context"> & {
  context: LoadContext
}

desktop/main.js

const url = await initRemix({
  // ...

  /** @type {import("~/context").LoadContext} */
  getLoadContext: () => ({
    secret: "123",
  }),
})

In a route file:

import type { DataFunctionArgs, LoadContext } from "~/context"

export async function loader({ context }: DataFunctionArgs) {
  // do something with context
}

Motivation

Electron has a comprehensive list of security recommendations to follow when building an app, especially if that app interacts with the web. Which includes, but is not limited to:

  • Using preload.js files to expose specific electron functionality to your app, via globals
  • Using IPC communication
  • Avoiding remote.require (which has since been removed)

These practices can lead to a lot of awkward boilerplate and splitting up related code across multiple files and domains.

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

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

Thinking about it another way: it's like a normal Remix web app, except Electron is your backend.

More Repositories

1

reacord

Create interactive Discord messages using React. βš›
TypeScript
752
star
2

remix-tailwind

Use TailwindCSS with Remix without an extra build step!
TypeScript
82
star
3

typescript-plugin-tw-template

Provides editor support for tailwind tw`...` tagged template syntax
TypeScript
53
star
4

vite-plugin-babel-macros

TypeScript
52
star
5

gatekeeper

supercharge your discord commands by gatekeeping them in a flow of reactivity β›“βš‘
TypeScript
52
star
6

simple-rsc-deno

TypeScript
31
star
7

anigreen

an extension of AniList, making it easier to track watched anime ✨
TypeScript
18
star
8

website

TypeScript
17
star
9

super-mario-typescript

Meth Meth Method's "Writing Super Mario in JavaScript" series, in TypeScript
TypeScript
16
star
10

reacord-starter

TypeScript
16
star
11

astromix

TypeScript
11
star
12

thoughtbucket

organize your ideas in a neat and cozy bucket (so they don't get jumbled around and lost like mine πŸ™ƒ)
TypeScript
11
star
13

jest-ts-babel-demo

JavaScript
11
star
14

hyperapp-flow-skeleton

A simple skeleton for getting started with hyperapp, webpack, and flowtype
JavaScript
9
star
15

simple-trello-clone

TypeScript
9
star
16

moodii

a simple and comfy app to help track your mood over time πŸ’œ
TypeScript
8
star
17

pulsecord

TypeScript
5
star
18

dms

deno module search cli
TypeScript
5
star
19

revalidate-thing

TypeScript
5
star
20

dnd-kit-masonry-demo

TypeScript
5
star
21

aoc2020

Kotlin
4
star
22

turntable

TypeScript
4
star
23

generate-index

a vscode extension for generating index files (TS only)
TypeScript
4
star
24

remix-fetcher-scrolls-to-top

TypeScript
3
star
25

online-pug-compiler

JavaScript
3
star
26

git-yeeted

USE AT YOUR OWN RISK. i made this because i had too many junk repos and deleting them individually is annoying lol
TypeScript
3
star
27

fontme

TypeScript
2
star
28

aspects-vtt

TypeScript
2
star
29

remix-tailwind-dev-bug

TypeScript
2
star
30

charge-worlds

TypeScript
2
star
31

stream-overlay

TypeScript
2
star
32

react-fastify-ssr

TypeScript
2
star
33

remix-deno-modern

TypeScript
2
star
34

mastercss-remix-test

TypeScript
2
star
35

aoc2019

let's try this advent of code thingy, how hard could it be
Kotlin
2
star
36

craftbang

don't ask why i revived this i was bored
2
star
37

remix-express-ts

TypeScript
1
star
38

character-creator

JavaScript
1
star
39

laplus

TypeScript
1
star
40

hi-bun

TypeScript
1
star
41

rhythm-game-thing

GDScript
1
star
42

wd-native

TypeScript
1
star
43

next-old

TypeScript
1
star
44

convex-effect

TypeScript
1
star
45

image-editor

TypeScript
1
star
46

musicbot

Kotlin
1
star
47

potion-brewing-deck-builder

TypeScript
1
star
48

number-guess-bot

TypeScript
1
star
49

rhythm-game-dart

Dart
1
star
50

reddit-client

TypeScript
1
star
51

anigreen-old

TypeScript
1
star
52

rpgbot

TypeScript
1
star
53

aoc2022

Nim
1
star
54

solid-lucide-bug

JavaScript
1
star
55

tfbg

falling box in godot
GDScript
1
star
56

astro-ts-intersection-build-error

Astro
1
star
57

configs

TypeScript
1
star
58

card-roguelike-godot

GDScript
1
star
59

oj-battle-sim

TypeScript
1
star
60

godot-multiplayer-demo

GDScript
1
star
61

bae

TypeScript
1
star
62

tsx-tsx-bug

TypeScript
1
star
63

video-grid-thing

TypeScript
1
star
64

the-button

CSS
1
star
65

food-game

TypeScript
1
star
66

zapdos-remixed

TypeScript
1
star
67

charge-worlds-old

TypeScript
1
star
68

a-distant-memory

TypeScript
1
star
69

aoc2021

Kotlin
1
star
70

typescript-test-plugin

TypeScript
1
star
71

game-of-arte

TypeScript
1
star
72

catboy-nexus-tabletop

TypeScript
1
star
73

eslint-astro-plugin-attribute-parse-error

Astro
1
star