Browse Source

chore: deprecate `event.sender` in `IpcRendererEvent`

Milan Burda 1 year ago
parent
commit
e56762f967

+ 1 - 1
docs/api/structures/ipc-renderer-event.md

@@ -1,6 +1,6 @@
 # IpcRendererEvent Object extends `Event`
 
-* `sender` [IpcRenderer](../ipc-renderer.md) - The `IpcRenderer` instance that emitted the event originally
+* `sender` [IpcRenderer](../ipc-renderer.md) _Deprecated_ - The `IpcRenderer` instance that emitted the event originally
 * `ports` [MessagePort][][] - A list of MessagePorts that were transferred with this message
 
 [MessagePort]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort

+ 10 - 0
docs/breaking-changes.md

@@ -146,6 +146,16 @@ app.on('gpu-process-crashed', (event, killed) => { /* ... */ })
 app.on('child-process-gone', (event, details) => { /* ... */ })
 ```
 
+### Deprecated: `event.sender` in `IpcRendererEvent`
+
+```js
+// Deprecated
+ipcRenderer.on('ping', (event) => event.sender.send('pong'))
+
+// Replace with
+ipcRenderer.on('ping', () => ipcRenderer.send('pong'))
+```
+
 ## Planned Breaking API Changes (27.0)
 
 ### Removed: macOS 10.13 / 10.14 support

+ 2 - 1
docs/fiddles/ipc/pattern-3/preload.js

@@ -1,5 +1,6 @@
 const { contextBridge, ipcRenderer } = require('electron/renderer')
 
 contextBridge.exposeInMainWorld('electronAPI', {
-  handleCounter: (callback) => ipcRenderer.on('update-counter', () => callback())
+  onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (event, value) => callback(value)),
+  counterValue: (value) => ipcRenderer.send('counter-value', value)
 })

+ 3 - 3
docs/fiddles/ipc/pattern-3/renderer.js

@@ -1,8 +1,8 @@
 const counter = document.getElementById('counter')
 
-window.electronAPI.handleCounter((event, value) => {
+window.electronAPI.onUpdateCounter((value) => {
   const oldValue = Number(counter.innerText)
   const newValue = oldValue + value
-  counter.innerText = newValue
-  event.sender.send('counter-value', newValue)
+  counter.innerText = newValue.toString()
+  window.electronAPI.counterValue(newValue)
 })

+ 18 - 7
docs/tutorial/ipc.md

@@ -429,7 +429,7 @@ modules in the preload script to expose IPC functionality to the renderer proces
 const { contextBridge, ipcRenderer } = require('electron')
 
 contextBridge.exposeInMainWorld('electronAPI', {
-  onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback)
+  onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (event, value) => callback(value))
 })
 ```
 
@@ -439,6 +439,8 @@ After loading the preload script, your renderer process should have access to th
 :::caution Security warning
 We don't directly expose the whole `ipcRenderer.on` API for [security reasons][]. Make sure to
 limit the renderer's access to Electron APIs as much as possible.
+Also don't just pass the callback to `ipcRenderer.on` as this will leak `ipcRenderer` via `event.sender`.
+Use a custom handler that invoke the `callback` only with the desired arguments.
 :::
 
 :::info
@@ -486,10 +488,10 @@ To tie it all together, we'll create an interface in the loaded HTML file that c
 Finally, to make the values update in the HTML document, we'll add a few lines of DOM manipulation
 so that the value of the `#counter` element is updated whenever we fire an `update-counter` event.
 
-```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(event:Electron.IpcRendererEvent,value:number)=>void)=>void}}
+```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(value:number)=>void)=>void}}
 const counter = document.getElementById('counter')
 
-window.electronAPI.onUpdateCounter((_event, value) => {
+window.electronAPI.onUpdateCounter((value) => {
   const oldValue = Number(counter.innerText)
   const newValue = oldValue + value
   counter.innerText = newValue.toString()
@@ -506,17 +508,26 @@ There's no equivalent for `ipcRenderer.invoke` for main-to-renderer IPC. Instead
 send a reply back to the main process from within the `ipcRenderer.on` callback.
 
 We can demonstrate this with slight modifications to the code from the previous example. In the
-renderer process, use the `event` parameter to send a reply back to the main process through the
+renderer process, expose another API to send a reply back to the main process through the
 `counter-value` channel.
 
-```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(event:Electron.IpcRendererEvent,value:number)=>void)=>void}}
+```javascript title='preload.js (Preload Script)'
+const { contextBridge, ipcRenderer } = require('electron')
+
+contextBridge.exposeInMainWorld('electronAPI', {
+  onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (event, value) => callback(value)),
+  counterValue: (value) => ipcRenderer.send('counter-value', value)
+})
+```
+
+```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(value:number)=>void)=>void,counterValue:(value:number)=>void}}
 const counter = document.getElementById('counter')
 
-window.electronAPI.onUpdateCounter((event, value) => {
+window.electronAPI.onUpdateCounter((value) => {
   const oldValue = Number(counter.innerText)
   const newValue = oldValue + value
   counter.innerText = newValue.toString()
-  event.sender.send('counter-value', newValue)
+  window.electronAPI.counterValue(newValue)
 })
 ```
 

+ 2 - 0
filenames.auto.gni

@@ -144,6 +144,7 @@ auto_filenames = {
   sandbox_bundle_deps = [
     "lib/common/api/native-image.ts",
     "lib/common/define-properties.ts",
+    "lib/common/deprecate.ts",
     "lib/common/ipc-messages.ts",
     "lib/common/web-view-methods.ts",
     "lib/common/webpack-globals-provider.ts",
@@ -269,6 +270,7 @@ auto_filenames = {
     "lib/common/api/native-image.ts",
     "lib/common/api/shell.ts",
     "lib/common/define-properties.ts",
+    "lib/common/deprecate.ts",
     "lib/common/init.ts",
     "lib/common/ipc-messages.ts",
     "lib/common/reset-search-paths.ts",

+ 10 - 1
lib/renderer/common-init.ts

@@ -1,5 +1,6 @@
 import { ipcRenderer } from 'electron/renderer';
 import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
+import * as deprecate from '@electron/internal/common/deprecate';
 
 import type * as webViewInitModule from '@electron/internal/renderer/web-view/web-view-init';
 import type * as windowSetupModule from '@electron/internal/renderer/window-setup';
@@ -19,7 +20,15 @@ const isWebView = mainFrame.getWebPreference('isWebView');
 v8Util.setHiddenValue(global, 'ipcNative', {
   onMessage (internal: boolean, channel: string, ports: MessagePort[], args: any[]) {
     const sender = internal ? ipcRendererInternal : ipcRenderer;
-    sender.emit(channel, { sender, ports }, ...args);
+    const event = { ports };
+    const warn = deprecate.warnOnce('event.sender', 'ipcRenderer');
+    Object.defineProperty(event, 'sender', {
+      get: () => {
+        warn();
+        return sender;
+      }
+    });
+    sender.emit(channel, event, ...args);
   }
 });