braebo / sveltekit-electron

Minimal Sveltekit + Electron starter template.
MIT License
269 stars 27 forks source link

IPC with Vite / svelte-kit #7

Closed bjbk closed 3 years ago

bjbk commented 3 years ago

Hello! Thanks for such a great template! 🚀

I cannot seem to get interprocess communication working. Now that remote has been depreciated, in a project I have using Vue/webpack everything is converted to IPC. All good.

At first I thought it may be because of using an older version of this template, but persists after scaffolding a new project.

Possibly related issue vite-electron-builder #189

How can I get IPC to work with Svelte-Kit? Here is an error I am getting:

[svelte] 2:21:17 PM [vite] Error when evaluating SSR module /Users/redacted/Developer/redacted-dev/redacted/src/routes/__layout.svelte:
[svelte] TypeError: Cannot create proxy with a non-object as target or handler
[svelte]     at nodeRequire (/Users/redacted/Developer/redacted-dev/redacted/node_modules/vite/dist/node/chunks/dep-e9a16784.js:68214:12)
[svelte]     at ssrImport (/Users/redacted/Developer/redacted-dev/redacted/node_modules/vite/dist/node/chunks/dep-e9a16784.js:68164:20)
[svelte]     at eval (/Users/redacted/Developer/redacted-dev/redacted/src/routes/__layout.svelte:9:31)
[svelte]     at instantiateModule (/Users/redacted/Developer/redacted-dev/redacted/node_modules/vite/dist/node/chunks/dep-e9a16784.js:68197:166)
[svelte] Cannot create proxy with a non-object as target or handler
[svelte] TypeError: Cannot create proxy with a non-object as target or handler

I have not yet changed the webPreferences object from the template default.

webPreferences: {
  enableRemoteModule: true,
  contextIsolation: true,
  nodeIntegration: true,
  spellcheck: false,
  devTools: dev,
}

WebPrefs in my other project for comparison:

const webPrefs = {
    nodeIntegration: false,
    enableRemoteModule: false,
    contextIsolation: false
 }

Is the issue with the main process or renderer?

if I pass

// electron.cjs
mainWindow.webContents.send('my-channel', 'message')
…

in renderer (say in __layout.svelte):

import { ipcRenderer } from 'electron'

ipcRenderer.on('my-channel', (event, message) => {
  console.log(message) // Prints 'message'
})

Then I get the error mentioned above. Thanks for any insight and if this is beyond the scope of the template project then please accept my apologies.

braebo commented 3 years ago

Hey @bjbk, sorry for the delay, I've had limited time to look into this. It appears it may be related to a few vite related issues. Have you made any progress on this? I can take a closer look now that I've freed up a bit. I agree this is pretty important and would be great to solve for others who may face the problem.

bjbk commented 3 years ago

Thanks for looking into it. Again, this is a great template and just keeps getting better! 😄

No progress on it yet. I agree, seems to be a Vite issue so probably not an issue with Sveltekit-electron in itself. If I find a solution I'll be sure to update this issue. Cheers!

bjbk commented 3 years ago

500 response:

ReferenceError: __dirname is not defined
    at node_modules/electron/index.js (http://localhost:3000/node_modules/.vite/electron.js?v=4b67ba10:50:30)
    at __require (http://localhost:3000/node_modules/.vite/electron.js?v=4b67ba10:6:44)
    at http://localhost:3000/node_modules/.vite/electron.js?v=4b67ba10:67:24
bjbk commented 3 years ago

I would seem one needs a preload script. https://www.electronjs.org/docs/api/context-bridge#contextbridge

Getting closer to a solution

bjbk commented 3 years ago

The response from main process can be wrapped in a browser check. See: https://kit.svelte.dev/faq

// preload.cjs

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
  'api', {
  send: (channel, data) => {
    ipcRenderer.send(channel, data)
  },
  sendSync: (channel, data) => {
    ipcRenderer.sendSync(channel, data)
  },
  receive: (channel, func) => {
    ipcRenderer.on(channel, (event, ...args) => func(...args))
  }

Main process:

// electron.cjs

…
ipcMain.on('to-main', (event, args) => {
  return mainWindow.webContents.send('from-main', 'hi from main');
})
…

in Svelte component:

<script>
import { browser } from '$app/env'

let desktop;

if (browser) {
  window.api.receive('from-main', (data) => {
    console.log(data);
    desktop = `Received ${data} from main process`;
  });
}

const handleClick = () => {
  window.api.send('to-main', 'a message');
}
</script>

https://stackoverflow.com/a/59888788/4727183

bjbk commented 3 years ago

@FractalHQ this seems to solve the problem. Not an issue with the template, but rather just proper implementation. Closing.