1
|
1
|
new file mode 100644
|
...
|
...
|
@@ -0,0 +1,105 @@
|
|
0
|
+---
|
|
1
|
+layout: post
|
|
2
|
+title: "Integrate native Node.js modules into an Electron app (2/2)"
|
|
3
|
+date: 2018-02-28 21:48
|
|
4
|
+comments: true
|
|
5
|
+categories: [javascript]
|
|
6
|
+cover: /images/cover/avatar.png
|
|
7
|
+keywords:
|
|
8
|
+description:
|
|
9
|
+---
|
|
10
|
+
|
|
11
|
+### tl;dr
|
|
12
|
+
|
|
13
|
+- package an Electron app into OS-specific bundle
|
|
14
|
+- save space by keeping only a few needed `node_modules` directories—tips & tricks
|
|
15
|
+
|
|
16
|
+# Current state
|
|
17
|
+
|
|
18
|
+[So we've got super simple app which uses node.js features thanks to Electron](/2018/02/22/integrate-native-node-dot-js-modules-into-an-electron-app-1-slash-2/). 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)?
|
|
19
|
+
|
|
20
|
+# Overview and planning
|
|
21
|
+
|
|
22
|
+We'll be using [electron-packager](https://github.com/electron-userland/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.
|
|
23
|
+
|
|
24
|
+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](https://github.com/webpack/webpack/releases/tag/v4.0.0) you can use nice new features related to development/production mode.
|
|
25
|
+
|
|
26
|
+# Organize package.json
|
|
27
|
+
|
|
28
|
+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.
|
|
29
|
+
|
|
30
|
+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.
|
|
31
|
+
|
|
32
|
+Notice deps groups:
|
|
33
|
+
|
|
34
|
+{% codeblock package.json lang:json %}
|
|
35
|
+{
|
|
36
|
+ "name": "electron-tutorial",
|
|
37
|
+ "main": "index.electron.js",
|
|
38
|
+ "scripts": {
|
|
39
|
+ "build": "webpack",
|
|
40
|
+ "electron": "electron .",
|
|
41
|
+ "test": "jest"
|
|
42
|
+ },
|
|
43
|
+ "dependencies": {
|
|
44
|
+ "bindings": "^1.3.0"
|
|
45
|
+ },
|
|
46
|
+ "devDependencies": {
|
|
47
|
+ "electron": "^1.8.2",
|
|
48
|
+ "electron-packager": "^11.0.1",
|
|
49
|
+ "electron-rebuild": "^1.7.3",
|
|
50
|
+ "jest": "^22.4.0",
|
|
51
|
+ "serialport": "^6.0.5",
|
|
52
|
+ "webpack": "^3.11.0"
|
|
53
|
+ }
|
|
54
|
+}
|
|
55
|
+{% endcodeblock %}
|
|
56
|
+
|
|
57
|
+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).
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+{% codeblock index.electron.js lang:javascript %}
|
|
61
|
+const { app, BrowserWindow } = require('electron');
|
|
62
|
+const Raven = require('raven');
|
|
63
|
+const os = require('os');
|
|
64
|
+const isDev = require('electron-is-dev');
|
|
65
|
+
|
|
66
|
+const isBundled = !isDev;
|
|
67
|
+
|
|
68
|
+if (process.env.NODE_ENV === 'production') {
|
|
69
|
+ Raven.config('XXX', {
|
|
70
|
+ captureUnhandledRejections: true,
|
|
71
|
+ tags: {
|
|
72
|
+ process: process.type,
|
|
73
|
+ electron: process.versions.electron,
|
|
74
|
+ chrome: process.versions.chrome,
|
|
75
|
+ platform: os.platform(),
|
|
76
|
+ platform_release: os.release()
|
|
77
|
+ }
|
|
78
|
+ }).install();
|
|
79
|
+}
|
|
80
|
+
|
|
81
|
+// ...rest of electron main file
|
|
82
|
+{% endcodeblock %}
|
|
83
|
+
|
|
84
|
+I would keep `raven` and `electron-is-dev` in `dependencies` group.
|
|
85
|
+
|
|
86
|
+# Make sure there are native modules
|
|
87
|
+
|
|
88
|
+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](http://localhost:4000/2018/02/22/integrate-native-node-dot-js-modules-into-an-electron-app-1-slash-2/).
|
|
89
|
+
|
|
90
|
+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`.
|
|
91
|
+
|
|
92
|
+*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](https://github.com/TooTallNate/node-bindings/issues/29). 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"`*
|
|
93
|
+
|
|
94
|
+# Can I build the package finally?
|
|
95
|
+
|
|
96
|
+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`.
|
|
97
|
+
|
|
98
|
+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).
|
|
99
|
+
|
|
100
|
+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`.
|
|
101
|
+
|
|
102
|
+*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](https://github.com/npm/npm/issues/19356)).*
|
|
103
|
+
|
|
104
|
+
|