diff options
Diffstat (limited to 'packages')
-rw-r--r-- | packages/main/package.json | 6 | ||||
-rw-r--r-- | packages/main/src/devTools.ts | 49 | ||||
-rw-r--r-- | packages/main/src/index.ts | 66 | ||||
-rw-r--r-- | packages/main/src/stores/RootStore.ts | 12 | ||||
-rw-r--r-- | packages/preload/package.json | 4 | ||||
-rw-r--r-- | packages/preload/src/SophieRendererImpl.ts | 74 | ||||
-rw-r--r-- | packages/preload/src/index.ts | 11 | ||||
-rw-r--r-- | packages/renderer/package.json | 6 | ||||
-rw-r--r-- | packages/renderer/src/devTools.ts | 37 | ||||
-rw-r--r-- | packages/renderer/src/index.tsx | 23 | ||||
-rw-r--r-- | packages/renderer/tsconfig.json | 3 | ||||
-rw-r--r-- | packages/renderer/vite.config.js | 3 | ||||
-rw-r--r-- | packages/shared/package.json | 5 | ||||
-rw-r--r-- | packages/shared/src/contextBridge/SophieRenderer.ts | 6 | ||||
-rw-r--r-- | packages/shared/src/index.ts | 11 | ||||
-rw-r--r-- | packages/shared/src/ipc/MainToRendererIpcMessage.ts | 4 | ||||
-rw-r--r-- | packages/shared/src/ipc/RendererIpcMessage.ts | 3 | ||||
-rw-r--r-- | packages/shared/src/ipc/RendererToMainIpcMessage.ts | 4 | ||||
-rw-r--r-- | packages/shared/src/stores/SharedStore.ts | 23 | ||||
-rw-r--r-- | packages/shared/vite.config.js | 8 |
20 files changed, 302 insertions, 56 deletions
diff --git a/packages/main/package.json b/packages/main/package.json index 63da432..22afafa 100644 --- a/packages/main/package.json +++ b/packages/main/package.json | |||
@@ -9,11 +9,13 @@ | |||
9 | }, | 9 | }, |
10 | "dependencies": { | 10 | "dependencies": { |
11 | "@sophie/shared": "workspace:*", | 11 | "@sophie/shared": "workspace:*", |
12 | "electron": "^16.0.5" | 12 | "electron": "^16.0.5", |
13 | "mobx": "^6.3.10", | ||
14 | "mobx-state-tree": "^5.1.0" | ||
13 | }, | 15 | }, |
14 | "devDependencies": { | 16 | "devDependencies": { |
15 | "@types/electron-devtools-installer": "^2.2.0", | 17 | "@types/electron-devtools-installer": "^2.2.0", |
16 | "@types/node": "^16.11.15", | 18 | "@types/node": "^16.11.17", |
17 | "electron-devtools-installer": "^3.2.0", | 19 | "electron-devtools-installer": "^3.2.0", |
18 | "typescript": "^4.5.4", | 20 | "typescript": "^4.5.4", |
19 | "vite": "^2.7.6" | 21 | "vite": "^2.7.6" |
diff --git a/packages/main/src/devTools.ts b/packages/main/src/devTools.ts new file mode 100644 index 0000000..d02bfbf --- /dev/null +++ b/packages/main/src/devTools.ts | |||
@@ -0,0 +1,49 @@ | |||
1 | import type { App, BrowserWindow } from 'electron'; | ||
2 | |||
3 | /** | ||
4 | * Installs the react and redux developer tools extensions. | ||
5 | * | ||
6 | * We use the redux devtools and connect the mobx store to it with `mst-middlewares`, | ||
7 | * because the mobx-state-tree devtools are currently unmaintained. | ||
8 | * | ||
9 | * @param app The electron application instance. | ||
10 | */ | ||
11 | export function installDevToolsExtensions(app: App): void { | ||
12 | app.whenReady().then(async () => { | ||
13 | const { | ||
14 | default: installExtension, | ||
15 | REACT_DEVELOPER_TOOLS, | ||
16 | REDUX_DEVTOOLS, | ||
17 | } = await import('electron-devtools-installer'); | ||
18 | installExtension( | ||
19 | [ | ||
20 | REACT_DEVELOPER_TOOLS, | ||
21 | REDUX_DEVTOOLS, | ||
22 | ], | ||
23 | { | ||
24 | forceDownload: false, | ||
25 | loadExtensionOptions: { | ||
26 | allowFileAccess: true, | ||
27 | }, | ||
28 | }, | ||
29 | ); | ||
30 | }).catch((err) => { | ||
31 | console.error('Failed to install devtools extension', err); | ||
32 | }); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * Opens the developer tools while applying a workaround to enable the redux devtools. | ||
37 | * | ||
38 | * @param browserWindow The browser window to open the devtools in. | ||
39 | * @see https://github.com/MarshallOfSound/electron-devtools-installer/issues/195#issuecomment-998872878 | ||
40 | */ | ||
41 | export function openDevToolsWhenReady(browserWindow: BrowserWindow): void { | ||
42 | const { webContents } = browserWindow; | ||
43 | webContents.once('dom-ready', () => { | ||
44 | webContents.once('devtools-opened', () => { | ||
45 | browserWindow?.focus(); | ||
46 | }); | ||
47 | webContents.openDevTools(); | ||
48 | }); | ||
49 | } | ||
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 @@ | |||
1 | import { app, BrowserWindow } from 'electron'; | 1 | import { app, BrowserWindow } from 'electron'; |
2 | import { getSnapshot, onPatch } from 'mobx-state-tree'; | ||
2 | import { join } from 'path'; | 3 | import { join } from 'path'; |
3 | import { RendererIpcMessage } from '@sophie/shared'; | 4 | import { |
5 | MainToRendererIpcMessage, | ||
6 | RendererToMainIpcMessage, | ||
7 | } from '@sophie/shared'; | ||
4 | import { URL } from 'url'; | 8 | import { URL } from 'url'; |
5 | 9 | ||
10 | import { | ||
11 | installDevToolsExtensions, | ||
12 | openDevToolsWhenReady, | ||
13 | } from './devTools'; | ||
14 | import { rootStore } from './stores/RootStore'; | ||
15 | |||
6 | const isSingleInstance = app.requestSingleInstanceLock(); | 16 | const isSingleInstance = app.requestSingleInstanceLock(); |
7 | const isDevelopment = import.meta.env.MODE === 'development'; | 17 | const isDevelopment = import.meta.env.MODE === 'development'; |
8 | 18 | ||
@@ -14,62 +24,46 @@ if (!isSingleInstance) { | |||
14 | app.enableSandbox(); | 24 | app.enableSandbox(); |
15 | 25 | ||
16 | if (isDevelopment) { | 26 | if (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 | ||
40 | let mainWindow: BrowserWindow | null = null; | 30 | let mainWindow: BrowserWindow | null = null; |
41 | 31 | ||
32 | const store = rootStore.create({ | ||
33 | shared: { | ||
34 | clickCount: 1, | ||
35 | }, | ||
36 | }); | ||
37 | |||
42 | function createWindow(): Promise<void> { | 38 | function 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(); |
diff --git a/packages/main/src/stores/RootStore.ts b/packages/main/src/stores/RootStore.ts new file mode 100644 index 0000000..a9c1290 --- /dev/null +++ b/packages/main/src/stores/RootStore.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | import { Instance, types } from 'mobx-state-tree'; | ||
2 | import { sharedStore } from '@sophie/shared'; | ||
3 | |||
4 | export const rootStore = types.model('RootStore', { | ||
5 | shared: sharedStore, | ||
6 | }).actions((self) => ({ | ||
7 | buttonClick() { | ||
8 | self.shared.clickCount += 1; | ||
9 | }, | ||
10 | })); | ||
11 | |||
12 | export interface RootStore extends Instance<typeof rootStore> {} | ||
diff --git a/packages/preload/package.json b/packages/preload/package.json index 5556c10..2ad215c 100644 --- a/packages/preload/package.json +++ b/packages/preload/package.json | |||
@@ -10,7 +10,9 @@ | |||
10 | }, | 10 | }, |
11 | "dependencies": { | 11 | "dependencies": { |
12 | "@sophie/shared": "workspace:*", | 12 | "@sophie/shared": "workspace:*", |
13 | "electron": "^16.0.5" | 13 | "electron": "^16.0.5", |
14 | "mobx": "^6.3.10", | ||
15 | "mobx-state-tree": "^5.1.0" | ||
14 | }, | 16 | }, |
15 | "devDependencies": { | 17 | "devDependencies": { |
16 | "typescript": "^4.5.4", | 18 | "typescript": "^4.5.4", |
diff --git a/packages/preload/src/SophieRendererImpl.ts b/packages/preload/src/SophieRendererImpl.ts new file mode 100644 index 0000000..e03c89e --- /dev/null +++ b/packages/preload/src/SophieRendererImpl.ts | |||
@@ -0,0 +1,74 @@ | |||
1 | import { ipcRenderer } from 'electron'; | ||
2 | import type { IJsonPatch } from 'mobx-state-tree'; | ||
3 | import { | ||
4 | MainToRendererIpcMessage, | ||
5 | RendererToMainIpcMessage, | ||
6 | sharedStore, | ||
7 | SharedStoreListener, | ||
8 | SharedStoreSnapshotIn, | ||
9 | SophieRenderer | ||
10 | } from '@sophie/shared'; | ||
11 | |||
12 | export type MessageSender = (channel: RendererToMainIpcMessage, ...args: unknown[]) => void; | ||
13 | |||
14 | export class SophieRendererImpl implements SophieRenderer { | ||
15 | readonly #send: MessageSender; | ||
16 | |||
17 | #listener: SharedStoreListener | null = null; | ||
18 | |||
19 | #snapshot: SharedStoreSnapshotIn | null = null; | ||
20 | |||
21 | constructor(send: MessageSender) { | ||
22 | this.#send = send; | ||
23 | } | ||
24 | |||
25 | sharedStoreSnapshotReceived(snapshot: unknown): void { | ||
26 | if (sharedStore.is(snapshot)) { | ||
27 | if (this.#listener === null) { | ||
28 | this.#snapshot = snapshot; | ||
29 | } else { | ||
30 | this.#listener.onSnapshot(snapshot); | ||
31 | } | ||
32 | } else { | ||
33 | console.error('Received invalid snapshot', snapshot); | ||
34 | this.#snapshot = null; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | sharedStorePatchReceived(patch: unknown): void { | ||
39 | if (this.#listener !== null) { | ||
40 | // `mobx-state-tree` will validate the patch, so we can safely cast here. | ||
41 | this.#listener.onPatch(patch as IJsonPatch); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | setSharedStoreListener(listener: SharedStoreListener): void { | ||
46 | this.#listener = listener; | ||
47 | if (this.#snapshot !== null) { | ||
48 | listener.onSnapshot(this.#snapshot); | ||
49 | this.#snapshot = null; | ||
50 | } | ||
51 | this.#send(RendererToMainIpcMessage.SharedStoreSnapshotRequest); | ||
52 | } | ||
53 | |||
54 | buttonClick(): void { | ||
55 | this.#send(RendererToMainIpcMessage.ButtonClick); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | export function createSophieRenderer(): SophieRenderer { | ||
60 | const impl = new SophieRendererImpl(ipcRenderer.send); | ||
61 | |||
62 | ipcRenderer.on(MainToRendererIpcMessage.SharedStoreSnapshot, (_event, snapshot) => { | ||
63 | impl.sharedStoreSnapshotReceived(snapshot); | ||
64 | }); | ||
65 | |||
66 | ipcRenderer.on(MainToRendererIpcMessage.SharedStorePatch, (_event, patch) => { | ||
67 | impl.sharedStorePatchReceived(patch); | ||
68 | }); | ||
69 | |||
70 | return { | ||
71 | setSharedStoreListener: impl.setSharedStoreListener.bind(impl), | ||
72 | buttonClick: impl.buttonClick.bind(impl), | ||
73 | }; | ||
74 | } | ||
diff --git a/packages/preload/src/index.ts b/packages/preload/src/index.ts index 830901a..19d1285 100644 --- a/packages/preload/src/index.ts +++ b/packages/preload/src/index.ts | |||
@@ -1,10 +1,7 @@ | |||
1 | import { contextBridge, ipcRenderer } from 'electron'; | 1 | import { contextBridge } from 'electron'; |
2 | import { RendererIpcMessage, SophieRenderer } from '@sophie/shared'; | ||
3 | 2 | ||
4 | const sophieRenderer: SophieRenderer = { | 3 | import { createSophieRenderer } from './SophieRendererImpl'; |
5 | buttonClicked() { | 4 | |
6 | ipcRenderer.send(RendererIpcMessage.ButtonClicked); | 5 | const sophieRenderer = createSophieRenderer(); |
7 | } | ||
8 | }; | ||
9 | 6 | ||
10 | contextBridge.exposeInMainWorld('sophieRenderer', sophieRenderer); | 7 | contextBridge.exposeInMainWorld('sophieRenderer', sophieRenderer); |
diff --git a/packages/renderer/package.json b/packages/renderer/package.json index 559e668..ee627b4 100644 --- a/packages/renderer/package.json +++ b/packages/renderer/package.json | |||
@@ -14,13 +14,17 @@ | |||
14 | "@mui/icons-material": "^5.2.5", | 14 | "@mui/icons-material": "^5.2.5", |
15 | "@mui/material": "^5.2.5", | 15 | "@mui/material": "^5.2.5", |
16 | "@sophie/shared": "workspace:*", | 16 | "@sophie/shared": "workspace:*", |
17 | "mobx": "^6.3.10", | ||
18 | "mobx-state-tree": "^5.1.0", | ||
17 | "react": "^17.0.2", | 19 | "react": "^17.0.2", |
18 | "react-dom": "^17.0.2" | 20 | "react-dom": "^17.0.2" |
19 | }, | 21 | }, |
20 | "devDependencies": { | 22 | "devDependencies": { |
21 | "@types/react": "^17.0.37", | 23 | "@types/react": "^17.0.38", |
22 | "@types/react-dom": "^17.0.11", | 24 | "@types/react-dom": "^17.0.11", |
23 | "@vitejs/plugin-react": "^1.1.3", | 25 | "@vitejs/plugin-react": "^1.1.3", |
26 | "mst-middlewares": "^5.1.0", | ||
27 | "remotedev": "^0.2.9", | ||
24 | "typescript": "^4.5.4", | 28 | "typescript": "^4.5.4", |
25 | "vite": "^2.7.6" | 29 | "vite": "^2.7.6" |
26 | } | 30 | } |
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 @@ | |||
1 | import 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 | */ | ||
17 | async 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 | */ | ||
33 | export 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'; | |||
2 | import '@fontsource/roboto/400.css'; | 2 | import '@fontsource/roboto/400.css'; |
3 | import '@fontsource/roboto/500.css'; | 3 | import '@fontsource/roboto/500.css'; |
4 | import '@fontsource/roboto/700.css'; | 4 | import '@fontsource/roboto/700.css'; |
5 | import { applyPatch, applySnapshot } from 'mobx-state-tree'; | ||
5 | import Button from "@mui/material/Button"; | 6 | import Button from "@mui/material/Button"; |
6 | import CssBaseline from "@mui/material/CssBaseline"; | 7 | import CssBaseline from "@mui/material/CssBaseline"; |
7 | import { | 8 | import { |
@@ -10,6 +11,26 @@ import { | |||
10 | } from '@mui/material/styles'; | 11 | } from '@mui/material/styles'; |
11 | import React from 'react'; | 12 | import React from 'react'; |
12 | import { render } from 'react-dom'; | 13 | import { render } from 'react-dom'; |
14 | import { sharedStore } from '@sophie/shared'; | ||
15 | |||
16 | import { exposeToReduxDevtools } from './devTools'; | ||
17 | |||
18 | const isDevelopment = import.meta.env.MODE === 'development'; | ||
19 | |||
20 | const store = sharedStore.create(); | ||
21 | |||
22 | if (isDevelopment) { | ||
23 | exposeToReduxDevtools(store); | ||
24 | } | ||
25 | |||
26 | window.sophieRenderer.setSharedStoreListener({ | ||
27 | onSnapshot(snapshot) { | ||
28 | applySnapshot(store, snapshot); | ||
29 | }, | ||
30 | onPatch(patch) { | ||
31 | applyPatch(store, patch); | ||
32 | }, | ||
33 | }); | ||
13 | 34 | ||
14 | const theme = createTheme({ | 35 | const 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> |
diff --git a/packages/renderer/tsconfig.json b/packages/renderer/tsconfig.json index 668356c..8746462 100644 --- a/packages/renderer/tsconfig.json +++ b/packages/renderer/tsconfig.json | |||
@@ -7,6 +7,9 @@ | |||
7 | "dom", | 7 | "dom", |
8 | "dom.iterable", | 8 | "dom.iterable", |
9 | "esnext" | 9 | "esnext" |
10 | ], | ||
11 | "types": [ | ||
12 | "vite/client" | ||
10 | ] | 13 | ] |
11 | }, | 14 | }, |
12 | "references": [ | 15 | "references": [ |
diff --git a/packages/renderer/vite.config.js b/packages/renderer/vite.config.js index ff34b6d..87c2d0c 100644 --- a/packages/renderer/vite.config.js +++ b/packages/renderer/vite.config.js | |||
@@ -3,7 +3,6 @@ | |||
3 | /* eslint-env node */ | 3 | /* eslint-env node */ |
4 | 4 | ||
5 | import { builtinModules } from 'module'; | 5 | import { builtinModules } from 'module'; |
6 | import { join } from 'path'; | ||
7 | import react from '@vitejs/plugin-react'; | 6 | import react from '@vitejs/plugin-react'; |
8 | 7 | ||
9 | // `resolveJsonModule` is disabled for this package, but vite will load the json nevertheless. | 8 | // `resolveJsonModule` is disabled for this package, but vite will load the json nevertheless. |
@@ -36,6 +35,8 @@ const config = { | |||
36 | assetsDir: '.', | 35 | assetsDir: '.', |
37 | rollupOptions: { | 36 | rollupOptions: { |
38 | external: [ | 37 | external: [ |
38 | 'mst-middlewares', | ||
39 | 'remotedev', | ||
39 | ...builtinModules, | 40 | ...builtinModules, |
40 | ], | 41 | ], |
41 | }, | 42 | }, |
diff --git a/packages/shared/package.json b/packages/shared/package.json index ccde705..f49be47 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json | |||
@@ -3,6 +3,7 @@ | |||
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "main": "dist/index.cjs", | 5 | "main": "dist/index.cjs", |
6 | "module": "dist/index.es.js", | ||
6 | "types": "dist/index.d.ts", | 7 | "types": "dist/index.d.ts", |
7 | "scripts": { | 8 | "scripts": { |
8 | "build": "vite build", | 9 | "build": "vite build", |
@@ -11,5 +12,9 @@ | |||
11 | "devDependencies": { | 12 | "devDependencies": { |
12 | "typescript": "^4.5.4", | 13 | "typescript": "^4.5.4", |
13 | "vite": "^2.7.6" | 14 | "vite": "^2.7.6" |
15 | }, | ||
16 | "dependencies": { | ||
17 | "mobx": "^6.3.10", | ||
18 | "mobx-state-tree": "^5.1.0" | ||
14 | } | 19 | } |
15 | } | 20 | } |
diff --git a/packages/shared/src/contextBridge/SophieRenderer.ts b/packages/shared/src/contextBridge/SophieRenderer.ts index 91a0a3c..c878595 100644 --- a/packages/shared/src/contextBridge/SophieRenderer.ts +++ b/packages/shared/src/contextBridge/SophieRenderer.ts | |||
@@ -1,3 +1,7 @@ | |||
1 | import { SharedStoreListener } from '../stores/SharedStore'; | ||
2 | |||
1 | export interface SophieRenderer { | 3 | export interface SophieRenderer { |
2 | buttonClicked(): void; | 4 | setSharedStoreListener(listener: SharedStoreListener): void; |
5 | |||
6 | buttonClick(): void; | ||
3 | } | 7 | } |
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index f95675d..7f192bd 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts | |||
@@ -1,3 +1,12 @@ | |||
1 | export type { SophieRenderer } from './contextBridge/SophieRenderer'; | 1 | export type { SophieRenderer } from './contextBridge/SophieRenderer'; |
2 | 2 | ||
3 | export { RendererIpcMessage } from './ipc/RendererIpcMessage'; | 3 | export { MainToRendererIpcMessage } from './ipc/MainToRendererIpcMessage'; |
4 | export { RendererToMainIpcMessage } from './ipc/RendererToMainIpcMessage'; | ||
5 | |||
6 | export type { | ||
7 | SharedStore, | ||
8 | SharedStoreListener, | ||
9 | SharedStoreSnapshotIn, | ||
10 | SharedStoreSnapshotOut, | ||
11 | } from './stores/SharedStore'; | ||
12 | export { sharedStore } from './stores/SharedStore'; | ||
diff --git a/packages/shared/src/ipc/MainToRendererIpcMessage.ts b/packages/shared/src/ipc/MainToRendererIpcMessage.ts new file mode 100644 index 0000000..2ddca80 --- /dev/null +++ b/packages/shared/src/ipc/MainToRendererIpcMessage.ts | |||
@@ -0,0 +1,4 @@ | |||
1 | export enum MainToRendererIpcMessage { | ||
2 | SharedStoreSnapshot = "sophie-shared-store-snapshot", | ||
3 | SharedStorePatch = "sophie-shared-store-patch", | ||
4 | } | ||
diff --git a/packages/shared/src/ipc/RendererIpcMessage.ts b/packages/shared/src/ipc/RendererIpcMessage.ts deleted file mode 100644 index cfb87ae..0000000 --- a/packages/shared/src/ipc/RendererIpcMessage.ts +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | export enum RendererIpcMessage { | ||
2 | ButtonClicked = "button-clicked" | ||
3 | } | ||
diff --git a/packages/shared/src/ipc/RendererToMainIpcMessage.ts b/packages/shared/src/ipc/RendererToMainIpcMessage.ts new file mode 100644 index 0000000..c4c682d --- /dev/null +++ b/packages/shared/src/ipc/RendererToMainIpcMessage.ts | |||
@@ -0,0 +1,4 @@ | |||
1 | export enum RendererToMainIpcMessage { | ||
2 | SharedStoreSnapshotRequest = "sophie-shared-store-snapshot-request", | ||
3 | ButtonClick = "sophie-button-click" | ||
4 | } | ||
diff --git a/packages/shared/src/stores/SharedStore.ts b/packages/shared/src/stores/SharedStore.ts new file mode 100644 index 0000000..8933bca --- /dev/null +++ b/packages/shared/src/stores/SharedStore.ts | |||
@@ -0,0 +1,23 @@ | |||
1 | import { | ||
2 | IJsonPatch, | ||
3 | Instance, | ||
4 | types, | ||
5 | SnapshotIn, | ||
6 | SnapshotOut, | ||
7 | } from 'mobx-state-tree'; | ||
8 | |||
9 | export const sharedStore = types.model("SharedStore", { | ||
10 | clickCount: 0 | ||
11 | }); | ||
12 | |||
13 | export interface SharedStore extends Instance<typeof sharedStore> {} | ||
14 | |||
15 | export interface SharedStoreSnapshotIn extends SnapshotIn<typeof sharedStore> {} | ||
16 | |||
17 | export interface SharedStoreSnapshotOut extends SnapshotOut<typeof sharedStore> {} | ||
18 | |||
19 | export interface SharedStoreListener { | ||
20 | onSnapshot(snapshot: SharedStoreSnapshotIn): void; | ||
21 | |||
22 | onPatch(patch: IJsonPatch): void; | ||
23 | } | ||
diff --git a/packages/shared/vite.config.js b/packages/shared/vite.config.js index cbebb8a..05ec118 100644 --- a/packages/shared/vite.config.js +++ b/packages/shared/vite.config.js | |||
@@ -26,15 +26,15 @@ const config = { | |||
26 | outDir: 'dist', | 26 | outDir: 'dist', |
27 | lib: { | 27 | lib: { |
28 | entry: 'src/index.ts', | 28 | entry: 'src/index.ts', |
29 | formats: ['cjs'], | 29 | formats: ['cjs', 'es'], |
30 | fileName: (format) => format === 'cjs' ? 'index.cjs' : `index.${format}.js`, | ||
30 | }, | 31 | }, |
31 | rollupOptions: { | 32 | rollupOptions: { |
32 | external: [ | 33 | external: [ |
34 | 'mobx', | ||
35 | 'mobx-state-tree', | ||
33 | ...builtinModules, | 36 | ...builtinModules, |
34 | ], | 37 | ], |
35 | output: { | ||
36 | entryFileNames: '[name].cjs', | ||
37 | }, | ||
38 | }, | 38 | }, |
39 | emptyOutDir: false, // Do not remove `.d.ts` files. | 39 | emptyOutDir: false, // Do not remove `.d.ts` files. |
40 | brotliSize: false, | 40 | brotliSize: false, |