tl;dr
- package an Electron app into OS-specific bundle
- save space by keeping only a few needed
node_modules
directories—tips & tricks
Current state
So we’ve got super simple app which uses node.js features thanks to Electron. Let’s say it evolves into 100k LOC large app with dozens of dependencies (both browser-friendly and native node.js). How to produce a space-efficient bundle (in the context of Electron)?
Overview and planning
We’ll be using electron-packager to create a OS-specific distributable bundle (Electron bundle). After we build javascript (javascript bundle) we keep an eye on native modules location and node_modules
content inside Electron bundle.
Build production quality javascript bundle is webpack-specific (and probably also babel-specific). I won’t cover this part as it has nothing to do with to Electron. If you use newest Webpack 4.0 you can use nice new features related to development/production mode.
Organize package.json
Electron-packager copies node_modules
into the final Electron bundle (which is slow and isn’t space-efficient at all). The good news is it ignores all packages in devDependencies
group in package.json
. We’ll use that.
We need bindings
dependency to keep in Electron bundle node_modules
. The dependency is responsible for lazy loading of native node.js modules and cannot be part of javascript bundle. As it is a dependency of your project dependencies, it is not listed in package.json
. Simply do npm i --save bindings
. This can be tricky and can break things but yolo.
Notice deps groups:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
In projects I develop there’s usually a few non-Electron dependencies in the main Electron file (as seen in example below). Keep all non-Electron dependencies inside dependencies
group (unless you plan to bundle the main file with Webpack’s target: 'electron-main'
option).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
I would keep raven
and electron-is-dev
in dependencies
group.
Make sure there are native modules
Simply copy all native modules (*.node
) to build
directory (they should be built in production quality by default). I wrote a few words about them in the previous article.
There’s a tiny change in relectron-rebuild
command. By default it won’t rebuild modules in devDependencies
group. Run the command with t
option: ./node_modules/.bin/electron-rebuild -e node_modules/electron -t prod,dev
.
Note 1: I’ve run into this error while running Electron app: Uncaught Error: Could not find module root given file: "file:///Users/cinan/Coding/js/electron-tutorial/electron-tutorial-darwin-x64/electron-tutorial.app/Contents/Resources/app/build/app.js". Do you have a package.json file?
This is a known bug. There is a pull request (not yet merged), you can install fixed version with npm i --save "bindings@https://github.com/ArnsboMedia/node-bindings.git#fix-getFileName-method-for-electron-use"
Can I build the package finally?
First run PLATFORM=electron npm run build
to create a javacript bundle. Build native modules with ./node_modules/.bin/electron-rebuild -e node_modules/electron -t prod,dev
and copy them into build
directory: cp node_modules/serialport/build/Release/serialport.node build
.
Now run ./node_modules/.bin/electron-packager . --overwrite
and wait a minute. New Electron bundle will be created inside directory electron-tutorial-darwin-x64
(differs on Linux and Windows).
Check out node_modules
in Electron bundle (in macOS it is electron-tutorial-darwin-x64/electron-tutorial.app/Contents/Resources/app/node_modules
). There should be a single bindings
directory. On macOS you can run the product with open electron-tutorial-darwin-x64/electron-tutorial.app
.
Note 2: if you find out your node_modules
directory is empty (although there are dependencies
defined in package.json
) then upgrade to npm@next npm i -g npm@next
(related bug).