From 803b20b94b1f4808520c12cf1874e76824ec9e16 Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Tue, 19 Jul 2022 17:25:03 +0200 Subject: [PATCH 1/9] docs: new main -> renderers messageChannel example --- docs/tutorial/message-ports.md | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index 9f1e9bf467aff..f068b462ef6d7 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -84,6 +84,82 @@ process, you can listen for the `close` event by calling `port.on('close', ## Example use cases +### Setting up a MessageChannel between two renderers + +In this example, the main process sets up a MessageChannel, then sends each port +to a different renderer. This allows renderers to send messages to each other +without needing to use the main process as an in-between. + +```js +// main.js /////////////////////////////////////////////////////////////////// +const { BrowserWindow, app, MessageChannelMain } = require('electron') + +app.whenReady().then(async () => { + // create the windows + const mainWindow = new BrowserWindow({ + show: false, + webPreferences: { + contextIsolation: false, + nodeIntegration: true , + preload: 'preloadMain.js', + } + }) + + const secondaryWindow = BrowserWindow({ + show: false, + webPreferences: { + contextIsolation: false, + nodeIntegration: true , + preload: 'preloadSecondary.js', + } + }) + + + // set up the channel + const { port1, port2 } = new MessageChannelMain(); + + // once the webContents are ready, send a port to each webContents with postMessage + mainWindow.once('ready-to-show', () => { + mainWindow.webContents.postMessage('port', null, [port1]); + }); + + secondaryWindow.once('ready-to-show', () => { + secondaryWindow.webContents.postMessage('port', null, [port2]); + }); +}); + +``` +Then, in your preload scripts you recieve the port through IPC and set up the +listeners. + +```js +// preloadMain.js and preloadSecondary.js +const { ipcRenderer } = require('electron'); + +ipcRenderer.on('port', e => { + // we recieved a port, make it available to your app. + window.messagePort = e.ports[0]; + + window.messagePort.onmessage = messageEvent => { + // handle message + }; +}); +``` +In this example messagePort is bound to the `window` object directly. It is better +to use `contextIsolation` and set up specific contextBridge calls for each of your +expected messages, but for the simplicity of this example we don't. + +That means window.messagePort is globally available and you can call +`postMessage` on it from anywhere in your app to send a message to the other +renderer. + +```js +// elsewhere in your code to send a message to the other renderers message handler +window.messagePort.postmessage("ping"); +``` + + + ### Worker process In this example, your app has a worker process implemented as a hidden window. From faa85933365b25318d98ff6608e3adf21a9275ca Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Tue, 19 Jul 2022 17:28:08 +0200 Subject: [PATCH 2/9] consistent use of your --- docs/tutorial/message-ports.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index f068b462ef6d7..7316854bb22bf 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -95,7 +95,7 @@ without needing to use the main process as an in-between. const { BrowserWindow, app, MessageChannelMain } = require('electron') app.whenReady().then(async () => { - // create the windows + // create the windows. const mainWindow = new BrowserWindow({ show: false, webPreferences: { @@ -115,10 +115,10 @@ app.whenReady().then(async () => { }) - // set up the channel + // set up the channel. const { port1, port2 } = new MessageChannelMain(); - // once the webContents are ready, send a port to each webContents with postMessage + // once the webContents are ready, send a port to each webContents with postMessage. mainWindow.once('ready-to-show', () => { mainWindow.webContents.postMessage('port', null, [port1]); }); @@ -137,7 +137,7 @@ listeners. const { ipcRenderer } = require('electron'); ipcRenderer.on('port', e => { - // we recieved a port, make it available to your app. + // port received, make it globally available. window.messagePort = e.ports[0]; window.messagePort.onmessage = messageEvent => { From 146778c76c8ce9cb0af8685e84f85679a8bd050f Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Tue, 19 Jul 2022 17:35:54 +0200 Subject: [PATCH 3/9] fix a typo --- docs/tutorial/message-ports.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index 7316854bb22bf..9cbe7d2e23194 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -129,7 +129,7 @@ app.whenReady().then(async () => { }); ``` -Then, in your preload scripts you recieve the port through IPC and set up the +Then, in your preload scripts you receive the port through IPC and set up the listeners. ```js From 641b4798af008edeabcad31c137249903ef850cd Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Wed, 20 Jul 2022 17:22:16 +0200 Subject: [PATCH 4/9] linting --- docs/tutorial/message-ports.md | 40 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index 9cbe7d2e23194..d3068b530fc0a 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -98,52 +98,50 @@ app.whenReady().then(async () => { // create the windows. const mainWindow = new BrowserWindow({ show: false, - webPreferences: { + webPreferences: { contextIsolation: false, - nodeIntegration: true , - preload: 'preloadMain.js', + nodeIntegration: true, + preload: 'preloadMain.js' } }) const secondaryWindow = BrowserWindow({ show: false, - webPreferences: { + webPreferences: { contextIsolation: false, - nodeIntegration: true , - preload: 'preloadSecondary.js', + nodeIntegration: true, + preload: 'preloadSecondary.js' } }) - // set up the channel. - const { port1, port2 } = new MessageChannelMain(); - + const { port1, port2 } = new MessageChannelMain() + // once the webContents are ready, send a port to each webContents with postMessage. mainWindow.once('ready-to-show', () => { - mainWindow.webContents.postMessage('port', null, [port1]); - }); + mainWindow.webContents.postMessage('port', null, [port1]) + }) secondaryWindow.once('ready-to-show', () => { - secondaryWindow.webContents.postMessage('port', null, [port2]); - }); -}); - + secondaryWindow.webContents.postMessage('port', null, [port2]) + }) +}) ``` Then, in your preload scripts you receive the port through IPC and set up the listeners. ```js // preloadMain.js and preloadSecondary.js -const { ipcRenderer } = require('electron'); +const { ipcRenderer } = require('electron') ipcRenderer.on('port', e => { // port received, make it globally available. - window.messagePort = e.ports[0]; - + window.messagePort = e.ports[0] + window.messagePort.onmessage = messageEvent => { // handle message - }; -}); + } +}) ``` In this example messagePort is bound to the `window` object directly. It is better to use `contextIsolation` and set up specific contextBridge calls for each of your @@ -155,7 +153,7 @@ renderer. ```js // elsewhere in your code to send a message to the other renderers message handler -window.messagePort.postmessage("ping"); +window.messagePort.postmessage('ping') ``` From 9c19732a9840cc5a73c8e3d7ab9da47d190c186e Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Wed, 20 Jul 2022 17:30:31 +0200 Subject: [PATCH 5/9] markdown linting --- docs/tutorial/message-ports.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index d3068b530fc0a..6fc773b21d65c 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -86,9 +86,9 @@ process, you can listen for the `close` event by calling `port.on('close', ### Setting up a MessageChannel between two renderers -In this example, the main process sets up a MessageChannel, then sends each port -to a different renderer. This allows renderers to send messages to each other -without needing to use the main process as an in-between. +In this example, the main process sets up a MessageChannel, then sends each port +to a different renderer. This allows renderers to send messages to each other +without needing to use the main process as an in-between. ```js // main.js /////////////////////////////////////////////////////////////////// @@ -127,8 +127,9 @@ app.whenReady().then(async () => { }) }) ``` -Then, in your preload scripts you receive the port through IPC and set up the -listeners. + +Then, in your preload scripts you receive the port through IPC and set up the +listeners. ```js // preloadMain.js and preloadSecondary.js @@ -143,12 +144,13 @@ ipcRenderer.on('port', e => { } }) ``` + In this example messagePort is bound to the `window` object directly. It is better -to use `contextIsolation` and set up specific contextBridge calls for each of your +to use `contextIsolation` and set up specific contextBridge calls for each of your expected messages, but for the simplicity of this example we don't. -That means window.messagePort is globally available and you can call -`postMessage` on it from anywhere in your app to send a message to the other +That means window.messagePort is globally available and you can call +`postMessage` on it from anywhere in your app to send a message to the other renderer. ```js @@ -156,8 +158,6 @@ renderer. window.messagePort.postmessage('ping') ``` - - ### Worker process In this example, your app has a worker process implemented as a hidden window. From 6a99a2c8ba457aa0a879ebe91245a0ce3f0476f7 Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Thu, 21 Jul 2022 08:47:36 +0200 Subject: [PATCH 6/9] Update docs/tutorial/message-ports.md Co-authored-by: Erick Zhao --- docs/tutorial/message-ports.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index 6fc773b21d65c..ab50d7ba3acdf 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -90,8 +90,7 @@ In this example, the main process sets up a MessageChannel, then sends each port to a different renderer. This allows renderers to send messages to each other without needing to use the main process as an in-between. -```js -// main.js /////////////////////////////////////////////////////////////////// +```js title='main.js (Main Process)' const { BrowserWindow, app, MessageChannelMain } = require('electron') app.whenReady().then(async () => { From 2c97f5a5b8bbe287c1af208559d8c55794b22099 Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Thu, 21 Jul 2022 09:00:25 +0200 Subject: [PATCH 7/9] update code example headings, reference contextIsolation example --- docs/tutorial/message-ports.md | 40 ++++++++++++---------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index ab50d7ba3acdf..ddcacb7613a75 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -8,8 +8,7 @@ your app. Here is a very brief example of what a MessagePort is and how it works: -```js -// renderer.js /////////////////////////////////////////////////////////////// +```js title='renderer.js (Renderer Process)' // MessagePorts are created in pairs. A connected pair of message ports is // called a channel. const channel = new MessageChannel() @@ -28,8 +27,7 @@ port2.postMessage({ answer: 42 }) ipcRenderer.postMessage('port', null, [port1]) ``` -```js -// main.js /////////////////////////////////////////////////////////////////// +```js title='main.js (Main Process)' // In the main process, we receive the port. ipcMain.on('port', (event) => { // When we receive a MessagePort in the main process, it becomes a @@ -130,8 +128,7 @@ app.whenReady().then(async () => { Then, in your preload scripts you receive the port through IPC and set up the listeners. -```js -// preloadMain.js and preloadSecondary.js +```js title='preloadMain.js and preloadSecondary.js (Preload scripts)' const { ipcRenderer } = require('electron') ipcRenderer.on('port', e => { @@ -146,13 +143,14 @@ ipcRenderer.on('port', e => { In this example messagePort is bound to the `window` object directly. It is better to use `contextIsolation` and set up specific contextBridge calls for each of your -expected messages, but for the simplicity of this example we don't. +expected messages, but for the simplicity of this example we don't. You can find an +example of context isolation further down this page at [Communicating directly between the main process and the main world of a context-isolated page](#communicating-directly-between-the-main-process-and-the-main-world-of-a-context-isolated-page) That means window.messagePort is globally available and you can call `postMessage` on it from anywhere in your app to send a message to the other renderer. -```js +```js title='renderer.js (Renderer Process)' // elsewhere in your code to send a message to the other renderers message handler window.messagePort.postmessage('ping') ``` @@ -163,8 +161,7 @@ In this example, your app has a worker process implemented as a hidden window. You want the app page to be able to communicate directly with the worker process, without the performance overhead of relaying via the main process. -```js -// main.js /////////////////////////////////////////////////////////////////// +```js title='main.js (Main Process)' const { BrowserWindow, app, ipcMain, MessageChannelMain } = require('electron') app.whenReady().then(async () => { @@ -202,8 +199,7 @@ app.whenReady().then(async () => { }) ``` -```html - +```html title='worker.html' ``` -```html - +```html title='app.html'