11import { app , BrowserWindow } from 'electron' ;
2- import path from 'path ' ;
2+ import express from 'express ' ;
33import * as url from 'node:url' ;
4+ import path from 'path' ;
45
56const __dirname = url . fileURLToPath ( new URL ( '.' , import . meta. url ) ) ;
67
@@ -22,7 +23,68 @@ const createWindow = () => {
2223 if ( MAIN_WINDOW_VITE_DEV_SERVER_URL ) {
2324 mainWindow . loadURL ( MAIN_WINDOW_VITE_DEV_SERVER_URL ) ;
2425 } else {
25- mainWindow . loadFile ( path . join ( __dirname , `../renderer/${ MAIN_WINDOW_VITE_NAME } /index.html` ) ) ;
26+ /**
27+ * The PowerSync web SDK relies on SharedWorkers for multiple tab support.
28+ * Multiple tab support in Electron is required if multiple `BrowserWindow`s
29+ * require the PowerSync client simultaneously.
30+ *
31+ * The default solution of serving HTML assets from a file is sufficient if multiple
32+ * tab support is not required.
33+ *
34+ * ```js
35+ * mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`));
36+ * ```
37+ *
38+ * Extra steps are required if multiple tab support is required.
39+ *
40+ * Serving from a file results in `window.origin` being set as `file://`.
41+ *
42+ * Usually creating multiple `SharedWorker` instances from the same JS context should
43+ * link to the same instance of the shared worker. However, multiple worker instances
44+ * will be created if the origin is not the same. Apparently `file://` origins cause
45+ * the latter.
46+ *
47+ * For example:
48+ * ```js
49+ * const worker1 = new SharedWorker('url');
50+ * const worker2 = new SharedWorker('url');
51+ *```
52+ *
53+ * Should only create 1 instance of a SharedWorker with `worker1` and `worker2`
54+ * pointing to the same instance.
55+ *
56+ * When the content is served from a file `worker1` and `worker2` point to different
57+ * (unique) instances of the shared worker code.
58+ *
59+ * The PowerSync SDK relies on a single shared worker instance being present.
60+ *
61+ * See: https://github.com/electron/electron/issues/13952
62+ *
63+ * This serves the production HTML assets via a HTTP server. This sets the Window
64+ * origin to a the server address. This results in expected SharedWorker
65+ * functionality.
66+ */
67+ const expressApp = express ( ) ;
68+
69+ // The Vite production output should all be here.
70+ const bundleDir = path . join ( __dirname , `../renderer/${ MAIN_WINDOW_VITE_NAME } ` ) ;
71+
72+ // Serve the assets production assets
73+ expressApp . use ( express . static ( bundleDir ) ) ;
74+
75+ /**
76+ * If the port used here is dynamic e.g. `0` then the session would be cleared
77+ * if the port changes. A fixed port should be used in production.
78+ * Care should be taken when selecting this port to avoid conflicts.
79+ * This demo uses a random fixed port for demonstration purposes. More advanced
80+ * port management should be implemented if using this in production.
81+ */
82+ const port = process . env . PORT || 40031 ;
83+ const server = expressApp . listen ( port , ( ) => {
84+ mainWindow . loadURL ( `http://127.0.0.1:${ port } ` ) ;
85+ } ) ;
86+
87+ app . on ( 'quit' , ( ) => server . close ( ) ) ;
2688 }
2789
2890 // Open the DevTools.
0 commit comments