build-electron
Use ES modules in Electron now!
build-electron
is a simple build tool for main and preload code of your Electron app, so you don't have to setup a webpack build system yourself. The aim is to make it easier to get started building Electron apps, like it used to be. Note that build-electron
is not a boilerplate.
Background
Because Electron does not support ES Modules, and the Node ecosystem is shifting to ESM we are lacking an easy way to simply use ESM Node.js code and modules in our Electron projects. A boilerplate is possible, but it can get outdated quickly and hard to maintain with new updates. So I created this project in the spirit of Create React App. When Electron supports ESM in the future 🤞, build-electron
can simply be unplugged from the project and it will hopefully "just work".
Features
- Simple - Doesn't build frontend; less hairy logic
- Supports Webpack 5
- Customizable
- Building for production or watching
How to use
Note that this project provides Node.js code building only (main, preload) - not renderer code due to there being so many different languages and frameworks for that, and there are already excellent tools for building those. For React based Electron apps, I recommend pairing with Create React App (CRA).
yarn add -D build-electron concurrently wait-on
Put your Electron main ESM source code in src/main/index.js
and preload source in src/preload/index.js
.
Now create a configuration file in your project root build-electron.config.js
(project root means the same directory that you have your Electron project's package.json
file):
module.exports = {
mainEntry: 'src/main/index.js',
preloadEntry: 'src/preload/index.js',
outDir: 'build',
mainTarget: 'electron16.0-main',
preloadTarget: 'electron16.0-preload',
}
Add to your package.json
:
{
"main": "build/main.js",
"build": {
"files": [
"build/**/*"
]
},
"scripts": {
"start": "concurrently -k \"build-electron -d\" \"wait-on build/.build-electron-done && electron .\"",
"build": "build-electron"
}
See example folder structure:
📁 My Electron App
📄 package.json
📄 build-electron.config.js
📁 src
📁 main
📄 index.js
[more sources]
📁 preload
📄 index.js
[more sources]
📁 build
📄 main.js [generated by build-electron]
📄 preload.js [generated by build-electron]
Now you can start developing:
npm run start
And to build your production app:
npm run build && npm exec electron-builder --mac
Optionally add your frontend builder (for example CRA, see example below)
Using with Create React App
In this example we will use CRA and electron-builder, although it should be similar with any other framework too.
yarn create react-app my-awesome-app
cd my-awesome-app
yarn add -D build-electron electron electron-builder concurrently wait-on
Now let's create the project structure. Because CRA uses a particular directory structure (and src
is reserved for the frontend source), we have to adapt to that. The relevant structure will be like this:
📁 my-awesome-app
📁 src-main
📄 index.js
📁 src-preload
📄 index.js
📁 src
[React source]
📁 public
📄 main.js [generated by build-electron]
📄 preload.js [generated by build-electron]
📁 build [generated by CRA]
📁 dist [generated by electron-builder]
📄 package.json
📄 .gitignore
📁 src-main
- Source for the electron main process (where you create your BrowserWindow
). Entry point index.js
bundles to public/main.js
.📁 src-preload
- Source for the electron preload script. Entry point index.js
bundles to public/preload.js
.📁 src
- Static frontend React files processed by CRA and outputted into build
, along with files from public
.📁 public
- Output of build-electron
's entry points (src-main
and src-preload
), and is the input of the CRA build's static files.📁 dist
- Final production app output generated by electron-builder
.
Now create a configuration file in your project root build-electron.config.js
:
module.exports = {
mainEntry: 'src-main/index.js',
preloadEntry: 'src-preload/index.js',
outDir: 'public',
mainTarget: 'electron16.0-main',
preloadTarget: 'electron16.0-preload',
}
Relevant bits to add to your package.json
:
"main": "public/main.js",
"build": {
"extraMetadata": {
"main": "build/main.js"
},
"files": [
"build/**/*"
]
},
"scripts": {
"start": "concurrently -k \"BROWSER=none react-scripts start\" \"build-electron -d\" \"wait-on public/.build-electron-done http://localhost:3000 && electron .\"",
"build": "build-electron && react-scripts build",
"postinstall": "electron-builder install-app-deps"
}
Add to .gitignore
:
/build
/dist
/icon-build
/public/main.js
/public/preload.js
Now you can start developing:
npm run start
And to build your production app:
npm run build && npm exec electron-builder --mac
build-electron.config.js
options
Note that paths can be relative to project root or absolute.
mainEntry
- Electron's main entrypoint.preloadEntry
- Electron's preload entrypoint.mainExtraEntries
, preloadExtraEntries
- Include additional main or preload entrypoints:
- Key-value pairs, example:
{ 'name': 'path/to/source' }
outDir
- Output files to this path.externals
- Use this to exclude certain modules from being bundled, like native dependencies.customConfig
- Customize Webpack config for both main.js
and preload.js
customMainConfig
- Customize Webpack config just for main.js
customPreloadConfig
- Customize Webpack config just for preload.js
mainTarget
- Should use electronX.Y-main
. See Webpack targetpreloadTarget
- Should use electronX.Y-preload
. See Webpack target
build-electron
CLI
--config
, -c
- Override path to build-electron.config.js
(default is in project root)--dev
, -d
- Run in development mode with file watcher (default is production build + exit after finish)
Size optimizations
Make sure you follow these guidelines:
- Any npm dependencies that have binaries (native Node.js modules) must be in
dependencies
and included in the externals
options so they don't get bundled in - All other dependencies should be
devDependencies
to prevent them from being included by electron-builder.
Source Maps
yarn add -D source-map-support
Add to the top of src-main/index.js
:
import 'source-map-support/register';
TODO
Alternatives / inspiration
Development
To test in a consuming project (yarn v2+), add to its package.json
:
"resolutions": {
"build-electron": "portal:/path/to/build-electron"
}
then run yarn
.