aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/index.ts
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-23 13:40:47 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-23 15:48:30 +0100
commit950fb9be8061e2a26e0536b98c6a3ee230618f54 (patch)
treeb136dcc9add0d268a2e7a6288ec934a86d03b652 /packages/main/src/index.ts
parentfeat: Add shared package for electron ipc (diff)
downloadsophie-950fb9be8061e2a26e0536b98c6a3ee230618f54.tar.gz
sophie-950fb9be8061e2a26e0536b98c6a3ee230618f54.tar.zst
sophie-950fb9be8061e2a26e0536b98c6a3ee230618f54.zip
feat: Main to renderer store synchronization
Patches are send in one direction only, from the main to the renderer, so all actions have to go through the context bridge and the renderer IPC to modify the store in the renderer. This makes the store in the main process a single source of truth, which simplifies debugging and state persistence. The store in the renderer is connected to redux devtools for inspection, but playing back the state in the devtools won't change the sotre in main process.
Diffstat (limited to 'packages/main/src/index.ts')
-rw-r--r--packages/main/src/index.ts66
1 files changed, 32 insertions, 34 deletions
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts
index cd04276..dbe6890 100644
--- a/packages/main/src/index.ts
+++ b/packages/main/src/index.ts
@@ -1,8 +1,18 @@
1import { app, BrowserWindow } from 'electron'; 1import { app, BrowserWindow } from 'electron';
2import { getSnapshot, onPatch } from 'mobx-state-tree';
2import { join } from 'path'; 3import { join } from 'path';
3import { RendererIpcMessage } from '@sophie/shared'; 4import {
5 MainToRendererIpcMessage,
6 RendererToMainIpcMessage,
7} from '@sophie/shared';
4import { URL } from 'url'; 8import { URL } from 'url';
5 9
10import {
11 installDevToolsExtensions,
12 openDevToolsWhenReady,
13} from './devTools';
14import { rootStore } from './stores/RootStore';
15
6const isSingleInstance = app.requestSingleInstanceLock(); 16const isSingleInstance = app.requestSingleInstanceLock();
7const isDevelopment = import.meta.env.MODE === 'development'; 17const isDevelopment = import.meta.env.MODE === 'development';
8 18
@@ -14,62 +24,46 @@ if (!isSingleInstance) {
14app.enableSandbox(); 24app.enableSandbox();
15 25
16if (isDevelopment) { 26if (isDevelopment) {
17 app.whenReady().then(async () => { 27 installDevToolsExtensions(app);
18 const {
19 default: installExtension,
20 MOBX_DEVTOOLS,
21 REACT_DEVELOPER_TOOLS,
22 } = await import('electron-devtools-installer');
23 installExtension(
24 [
25 MOBX_DEVTOOLS,
26 REACT_DEVELOPER_TOOLS,
27 ],
28 {
29 forceDownload: false,
30 loadExtensionOptions: {
31 allowFileAccess: true,
32 },
33 },
34 );
35 }).catch((err) => {
36 console.error('Failed to install devtools extension', err);
37 });
38} 28}
39 29
40let mainWindow: BrowserWindow | null = null; 30let mainWindow: BrowserWindow | null = null;
41 31
32const store = rootStore.create({
33 shared: {
34 clickCount: 1,
35 },
36});
37
42function createWindow(): Promise<void> { 38function createWindow(): Promise<void> {
43 mainWindow = new BrowserWindow({ 39 mainWindow = new BrowserWindow({
44 show: false, 40 show: false,
41 autoHideMenuBar: true,
45 webPreferences: { 42 webPreferences: {
46 nativeWindowOpen: true, 43 nativeWindowOpen: true,
47 webviewTag: false, 44 webviewTag: false,
48 sandbox: true, 45 sandbox: true,
49 preload: join(__dirname, '../../preload/dist/index.cjs'), 46 preload: join(__dirname, '../../preload/dist/index.cjs'),
50 } 47 },
51 }); 48 });
52 49
53 const { webContents } = mainWindow;
54
55 // See https://github.com/MarshallOfSound/electron-devtools-installer/issues/195#issuecomment-998872878
56 if (isDevelopment) { 50 if (isDevelopment) {
57 webContents.once('dom-ready', () => { 51 openDevToolsWhenReady(mainWindow);
58 webContents.once('devtools-opened', () => {
59 mainWindow?.focus();
60 });
61 webContents.openDevTools();
62 });
63 } 52 }
64 53
65 mainWindow.on('ready-to-show', () => { 54 mainWindow.on('ready-to-show', () => {
66 mainWindow?.show(); 55 mainWindow?.show();
67 }); 56 });
68 57
58 const { webContents } = mainWindow;
59
69 webContents.on('ipc-message', (_event, channel, ...args) => { 60 webContents.on('ipc-message', (_event, channel, ...args) => {
70 switch (channel) { 61 switch (channel) {
71 case RendererIpcMessage.ButtonClicked: 62 case RendererToMainIpcMessage.SharedStoreSnapshotRequest:
72 console.log('Button clicked'); 63 webContents.send(MainToRendererIpcMessage.SharedStoreSnapshot, getSnapshot(store.shared));
64 break;
65 case RendererToMainIpcMessage.ButtonClick:
66 store.buttonClick();
73 break; 67 break;
74 default: 68 default:
75 console.warn('Unknown IPC message:', channel, args); 69 console.warn('Unknown IPC message:', channel, args);
@@ -77,6 +71,10 @@ function createWindow(): Promise<void> {
77 } 71 }
78 }); 72 });
79 73
74 onPatch(store.shared, (patch) => {
75 webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch);
76 });
77
80 const pageUrl = (isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined) 78 const pageUrl = (isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined)
81 ? import.meta.env.VITE_DEV_SERVER_URL 79 ? import.meta.env.VITE_DEV_SERVER_URL
82 : new URL('../renderer/dist/index.html', `file://${__dirname}`).toString(); 80 : new URL('../renderer/dist/index.html', `file://${__dirname}`).toString();