aboutsummaryrefslogtreecommitdiffstats
path: root/packages/renderer/src
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/renderer/src
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/renderer/src')
-rw-r--r--packages/renderer/src/devTools.ts37
-rw-r--r--packages/renderer/src/index.tsx23
2 files changed, 59 insertions, 1 deletions
diff --git a/packages/renderer/src/devTools.ts b/packages/renderer/src/devTools.ts
new file mode 100644
index 0000000..5930c48
--- /dev/null
+++ b/packages/renderer/src/devTools.ts
@@ -0,0 +1,37 @@
1import type { IAnyStateTreeNode } from 'mobx-state-tree';
2
3/**
4 * Connects the `model` to the redux devtools extension after loading the required
5 * dependencies asynchronously.
6 *
7 * We have to apply a workaround to load `remotedev` by shimming the `global` object,
8 * because `remotedev` uses an old version of `socketcluster-client` that refers to
9 * `global` instead of `globalThis`.
10 *
11 * Due to the old dependencies, this function is not safe to call in production.
12 * However, we don't bundle `remotedev` in production, so the call would fail anyways.
13 *
14 * @param model The store to connect to the redux devtools.
15 * @see https://github.com/SocketCluster/socketcluster-client/issues/118#issuecomment-469064682
16 */
17async function exposeToReduxDevtoolsAsync(model: IAnyStateTreeNode): Promise<void> {
18 (window as { global?: unknown }).global = window;
19
20 const [remotedev, { connectReduxDevtools }] = await Promise.all([
21 // @ts-ignore
22 import('remotedev'),
23 import('mst-middlewares'),
24 ]);
25 connectReduxDevtools(remotedev, model);
26}
27
28/**
29 * Connects the `model` to the redux devtools extension.
30 *
31 * @param model The store to connect to the redux devtools.
32 */
33export function exposeToReduxDevtools(model: IAnyStateTreeNode): void {
34 exposeToReduxDevtoolsAsync(model).catch((err) => {
35 console.error('Could not connect to Redux devtools', err);
36 });
37}
diff --git a/packages/renderer/src/index.tsx b/packages/renderer/src/index.tsx
index 452448c..37daaa6 100644
--- a/packages/renderer/src/index.tsx
+++ b/packages/renderer/src/index.tsx
@@ -2,6 +2,7 @@ import '@fontsource/roboto/300.css';
2import '@fontsource/roboto/400.css'; 2import '@fontsource/roboto/400.css';
3import '@fontsource/roboto/500.css'; 3import '@fontsource/roboto/500.css';
4import '@fontsource/roboto/700.css'; 4import '@fontsource/roboto/700.css';
5import { applyPatch, applySnapshot } from 'mobx-state-tree';
5import Button from "@mui/material/Button"; 6import Button from "@mui/material/Button";
6import CssBaseline from "@mui/material/CssBaseline"; 7import CssBaseline from "@mui/material/CssBaseline";
7import { 8import {
@@ -10,6 +11,26 @@ import {
10} from '@mui/material/styles'; 11} from '@mui/material/styles';
11import React from 'react'; 12import React from 'react';
12import { render } from 'react-dom'; 13import { render } from 'react-dom';
14import { sharedStore } from '@sophie/shared';
15
16import { exposeToReduxDevtools } from './devTools';
17
18const isDevelopment = import.meta.env.MODE === 'development';
19
20const store = sharedStore.create();
21
22if (isDevelopment) {
23 exposeToReduxDevtools(store);
24}
25
26window.sophieRenderer.setSharedStoreListener({
27 onSnapshot(snapshot) {
28 applySnapshot(store, snapshot);
29 },
30 onPatch(patch) {
31 applyPatch(store, patch);
32 },
33});
13 34
14const theme = createTheme({ 35const theme = createTheme({
15 palette: { 36 palette: {
@@ -24,7 +45,7 @@ function App() {
24 <CssBaseline enableColorScheme /> 45 <CssBaseline enableColorScheme />
25 <Button 46 <Button
26 variant="contained" 47 variant="contained"
27 onClick={window.sophieRenderer.buttonClicked} 48 onClick={window.sophieRenderer.buttonClick}
28 > 49 >
29 Hello Sophie! 50 Hello Sophie!
30 </Button> 51 </Button>