DEV Community

Cover image for Making Desktop apps with Electron, React Native, and Expo
Evan Bacon
Evan Bacon

Posted on

Making Desktop apps with Electron, React Native, and Expo

TL;DR: Example. Expo + Electron is in alpha (Nov 2019). docs = most recent info.

This tutorial will show you how to use React Native, Electron, Webpack, and the Expo SDK too create dope Desktop apps!

Electron is a great way to make desktop apps, and possibly the easiest. Lots of popular apps like VSCode, Figma, Zeplin, and many others are made with it! I like to think of it as a browser with extra native features like File System, Touch Bar, Menu Bar, Bluetooth, In-app Purchases.

Another great framework is Expo, you can use it to build mobile apps and websites with React. Expo for web works by using browser features with react-native-web whenever it can, then failing gracefully when features aren't available. 🤔 But what if Expo for web had access to all of the same features as a native app? That would probably look something like "Expo for Desktop" 😮.

🚀 Tutorial

Alt Text

TL;DR: Here is an example repo..

  • Create a new Expo project with expo init (you can select a TypeScript project from here if you want 🥰)
    • You may need to install or update the Expo CLI with npm i -g expo-cli
    • This project by default can already run on iOS, Android, and web or as a PWA.
  • cd into the project and run yarn add -D @expo/electron-adapter
    • This has all of the tools used to run Electron with Expo.
    • Notice that it's not built directly into Expo CLI (out-of-tree solution).
  • Now run yarn expo-electron to bootstrap the project. Currently this does the following:
    • Install the required dependencies: electron, @expo/webpack-config, react-native-web, etc...
    • Create a new electron-webpack config file electron-webpack.js and wraps it in the method withExpoAdapter which ensures that everything is setup correctly.
    • Append electron generated files to the .gitignore
  • Finally run yarn expo-electron start to start the project!
    • Everything should just open automatically.
    • You can view logs in the terminal.
    • Quit with "ctrl+c" in the terminal or by closing the browser window.
    • Make some changes to App.tsx to see the magic happen! 🧚‍♂️

Alt Text

🎨 Customizing the Main Process

If you're familiar with Electron you're probably wondering "what about the main process?" (but without the hyperlink).

Electron has 2 processes:

  • renderer process: which is where you'll write your React application code.
  • main process: Think of the "main process" as the native code in a React Native process (but still written with JavaScript). It's mostly unaware of the code running in the "renderer process", it has access to a variety of different features like creating windows.

📚 How it works

  • By default your project uses a main-process that runs in a hidden folder (node_modules/@expo/electron-adapter/...).
  • To customize the main process (highly recommended) you can run yarn expo-electron customize which will generate a folder /electron in your root directory.
  • You'll need to restart Electron for this new folder to become the new target.
    • Everything in electron/main has hot-reloading enabled (!!) so that should make your life happier.
    • the electron/webpack.config.js can be used to modify the Webpack config for both processes (use values passed to the method to detect which is which).

📂 File Structure

|- electron/
|-- webpack.config.js
|-- main/ All main process code goes in here
|--- index.js Entry point for your main process
|- dist/ Electron will generate files here, do not edit it directly.
|- electron-webpack.js Config file for the package electron-webpack which is required to run your project.
|- App.tsx || App.js The entry point of your renderer process, unless you change it in the package.json
|- src/ Not required, but you can put all of your renderer process code in here
|- assets/ All static assets, images, fonts, icons, SVGs, videos, etc...

⚙️ Building your project

At the time of writing this (Nov 2019) expo/electron-adapter doesn't provide any special building utils. But I've put together a guide for building a project with existing Electron packages: Expo Docs: Building Electron apps

🤭 Why Electron

"Why not just use a fully native solution like OSX and react-native-windows?" the reason is ... why not both! 🥳

Alt Text

In the future want to deliver the optimal experience for every platform, but we also really appreciate the ability to choose your stack. So for now you can use Electron, but in the future there will probably be even better native workflows provided by Expo.

🧸 Behavior

  • Webpack now resolves files with .electron.js & .web.js extensions in that order. If you want to use electron features then put them in a file like foo.electron.js.
  • Every universal package you have installed will be transpiled automatically, this includes packages that start with the name: expo, @expo, @unimodules, @react-navigation, react-navigation, react-native. You can add more by appending them to the array for key expo.web.build.babel.include in your app.json (this feature is experimental and subject to change).
  • I wrote the docs that I just blatantly lifted this section from :]

👋 Thanks so much

That's all for now, to stay updated on new features feel free to follow me on Twitter, Github, Dev..ehh...

Top comments (14)

Collapse
 
wernancheta profile image
Wern Ancheta • Edited

Thanks for writing this guide!
I tried creating a demo app with it and it works in development mode.

The only problem is that the build doesn't seem to work.
I'm getting this error when compiling in mac:

electron expo error

I used the following command to compile: yarn electron-webpack && yarn electron-builder --dir -c.compression=store -c.mac.identity=null

There were no errors in the compilation process. My babel.config.js looks like:

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo', 'module:metro-react-native-babel-preset', 'module:react-native-dotenv'], 
  };
};
Enter fullscreen mode Exit fullscreen mode

any ideas why this is? does babel-preset-expo support global module imports?

again, thank you for this. I'll continue trying to figure out what's wrong.

Collapse
 
aloaks profile image
Alberto Robles

Hi, there.

I'm getting a similar error. I've been trying to fix it by changing the syntax for that line from 'import from ...' to 'require('....')'.

It "worked" in the way that the error moved to the next "import" statement.
Is ES6 not working on the build?

Tried using other babel presets (babel/env, babel-react, etc...). With these ones, not even the building finishes.

Can't find any solution

Collapse
 
varmab profile image
Varma Bhupatiraju

@Wern, I have same issue. Did you find any solutions?

Collapse
 
meedwire profile image
Leonardo Silva

Any answer on the subject, I have the same problem, a build example would be welcome.

Collapse
 
comprider profile image
tsayyed

Any luck to create build for electron?

Collapse
 
evanbacon profile image
Evan Bacon

Wow that looks awesome! When you use Expo to make Electron apps you also get an iOS and Android app as well though.

Collapse
 
nickytonline profile image
Nick Taylor

Great stuff. Thanks for sharing Evan. I've done a lot of React, but still haven't touched any of the native stuff, including Expo. Maybe I should start. 😎

 
longebane profile image
Long Dao

Yes it technically can, but simply isn't supported at all at the moment.

Collapse
 
lfkwtz profile image
Michael Lefkowitz

Great post - I featured this on React Native Now newsletter #56

Collapse
 
evanbacon profile image
Evan Bacon

Awesome, thanks so much!

Collapse
 
seanmclem profile image
Seanmclem

Any way to run Expo app without having to download your JS bundle every time?

Collapse
 
arrygoo profile image
Aryan Goharzad

Yes,are you referring to during production or dev?

Collapse
 
kortbyoussama profile image
oussama benkortbi

really helpful post

i may need to figure out how can i resize the window and make use of electron

Collapse
 
arknoid profile image
Olivier Malige • Edited

Hello, I have problems with the implementation of Redux with this package...
Do you have any idea?

Thank you