electron howto
- electron best practice
- electron test
- sqlite best practice
- log electron
- build for Windows on Mac
- build native dependencies and for multi platforms
- custom app logo
- electron-builder
files
map - ⭐️⭐️⭐️ debug binary electron
ipcRenderer
communication- hwo to use
preload.ts
electron best practice
design of dependency workflow
How to organize your project structure quite depends on your project scale and realization.
For example, since my project is not too big, I combined almost all the constant variables into one file const.ts
in each module, containing channels
, error_types
, defined variables
, etc.
app path, storing db, log, etc
Since the userData
is the sub path of appData
with the name of our application, so it's better to put all of our data into userData
.
// src/main/base/utils.ts
export const getRootPath = () => app.getPath('userData');
export const getLogPath = () => path.join(getRootPath(), 'main.log');
export const getDbPath = () => path.join(getRootPath(), 'hjxh_data.sqlite');
!!!tip If run under the development, since the app is run via electron .
, so the userData
points to the Electron
, which is different from the real build version with the actual name defined in our package.json/build
.
ref:
log into file
log.transports.file.resolvePath = () => getLogPath();
log.transports.file.format = '{y}-{m}-{d} {h}:{i}:{s}.{ms} {level}: {text}';
ref:
electron test
When all the ts-node / esm
relative environment is prepared well, there still exists some problems.
For example, concerning about database, since I use it derived from app runtime, and then it would not be mocked unless we start our script as a real electron app rather than a script for unittest.
sqlite best practice
don't use relative path as sqlite position
When using relative path, many packages including system would treat it on the base of current process directory.
However, if the application is build into binary and run by click, then the behavior would become a bit different since e.g. in Mac the application is run with process.cwd() = '/'
.
And then if we write our data into a sqlite which is created with relative path, such as ./test.db
, then the error would arise up because of permission.
So the best practice is to use AppData
directory via path.join(app.getPath('appData'), dbName)
.
log electron
There are two places where console.log output goes:
If you log in the renderer process, you can see it in the console in the browser window. If you open the dev tools programmatically you can see this console even after building.
If you log in the main process, you can see these messages if you start the installed app or the unpacked binary via command line. In windows this would be the app.exe in the win-unpacked directory that electron-builder creates.
Another alternative would be a logger like electron-log
that writes the log messages into a configured file.
ref:
And I am surprised to find that it has been in the electron-react-typescript
boilerplate.
And it's used for Auto-Update
.
ref:
megahertz/electron-log: Just a simple logging module for your Electron application
logging - Where can I find the logs for my Electron app in production? - Stack Overflow
However, it may not work since the output still goes into the terminal.
TODO: idealog color configuration
build for Windows on Mac
Using this command:
electron-builder build --win
But then:
Hence, we need a mirror.
build native dependencies and for multi platforms
It seems this is auto finished by electron-builder
, which is described at: This module can automatically determine the version of Electron and handle the manual steps of downloading headers and rebuilding native modules for your app.
custom app logo
a good start
All we need to do is to follow: Changing electron app icon. Generate icns | by Khoa Pham | Fantageek | Medium
In which it directs us to download onmyway133/IconGenerator: 🍱 A macOS app to generate app icons
success when run after pack.
customize icon for unpacked app
If we wanner the icon does work in unpacked environment, we need to replace the default icon in the module.
cp ./assets/icon.icns node_modules/electron/dist/Electron.app/Contents/Resources
Or we can follow the above article, right click app, and change the icon.
square .icon
When I pack for windows, it told me the icon size is at least '256 x 256'.
However I checked the raw image xx.png
, and admitted that the size is far bigger than this, but only to be converted to '256 x 204'.
I realized it may be owing to the size ratio, and I changed the image file into a square one.
And then, it worked!
ref:
electron-builder files
map
The current problem has become clarified, that is files not found.
We need a map, since I tried files
but in vain.
Now, the problem is that the database would auto create after first query, while it's empty and then causes errors.
⭐️⭐️⭐️ debug binary electron
Here's what worked for me on Mac.
In terminal type lldb path/to/build.app
In the opened debugger type run --remote-debugging-port=8315
. It should open a window of your app. Open Chrome at http://localhost:8315/
Click on the name of the app. For example, Webpack App. If you don't see anything in the opened tab, focus on the window of your app.
ref: https://stackoverflow.com/a/56634497/9422455
ipcRenderer
communication
It deserves my attention that the msg interface from main process is so-called ipcMainEvent
which is not exported.
So, for typescript support, I need to define a 'hooked ipcMainEvent' like this:
interface IpcMainEvent extends Event {
// eslint-disable-next-line @typescript-eslint/ban-types
reply: Function;
}
And when communicating, I should be careful with the difference between on
and once
, and don't forget to close the channel if need.
ref:
hwo to use preload.ts
ref:
suppose:
MAIN: src/electron/main
RENDERER: src/renderer/index
PRELOAD_TS: src/electron/preload.ts
PRELOAD_JS: src/electron/preload.js
RUN_MAIN: electron MAIN, or like
RUN_RENDERER: webpack serve --config WEBPACK_DEV_CONFIG_RENDERER.js, or like
the preload
script won't run if we just start the main process
First, if we only run electron MAIN
or electron -r ts-node/register/transpile-only MAIN
(ts support), the electron window would run successfully no matter we pointed a preload
file or not since the file would only run just before the renderer process, i.e. after the main process and separate.
it's ok when we just use preload.js
If we just use preload.js
, then no matter we use webpack or not, the programme would run well.
what about using a preload.ts
The main problem concerning with preload.ts
is that when we use electron, we are likely to use different pack method for main process and the renderer one, and the core concept is whether the preload.ts
had been compiled into preload.js
and executed by the renderer.
remedy 1, the tsc
solution
If we first created a preload.ts
file and it doesn't export anything to with the main or renderer codes, then the only change we need to do is that to add tsc PRELOAD_TS &&
before the RUN_RENDERER
.
It can be expected to see the preload.ts
changed into preload.js
and all the things goes ok.
For example, we can write pure ts
type of preload
, and it in fact needs no extra modification since the interface is perfect except a little dangerous since we didn't put constraint on the api request. More can be found refer to: Security considerations
I do care about the safe problem if this is a huge app developed for commercial use.
But If I write more apis, then it would drive me to separate my apis in another file, and the renderer, as well as the main, would read from the file together. At the same time, tsc
would compile the preload.ts
along with the separate file to .js
, then a emit skipped
error may happen if the electron main to read a interface.ts
file but to find there exists both interface.ts
and interface.js
.
how to remedy the electron-react-boilerplate
project
Dive into the source coe of electron-react-boilerplate , we can know the programme startup flow under the development environment is as the following: