|
| 1 | +# contextBridge |
| 2 | + |
| 3 | +> Create a safe, bi-directional, synchronous bridge across isolated contexts |
| 4 | +
|
| 5 | +Process: [Renderer](../glossary.md#renderer-process) |
| 6 | + |
| 7 | +An example of exposing an API to a renderer from an isolated preload script is given below: |
| 8 | + |
| 9 | +```javascript |
| 10 | +// Preload (Isolated World) |
| 11 | +const { contextBridge, ipcRenderer } = require('electron') |
| 12 | + |
| 13 | +contextBridge.exposeInMainWorld( |
| 14 | + 'electron', |
| 15 | + { |
| 16 | + doThing: () => ipcRenderer.send('do-a-thing') |
| 17 | + } |
| 18 | +) |
| 19 | +``` |
| 20 | + |
| 21 | +```javascript |
| 22 | +// Renderer (Main World) |
| 23 | + |
| 24 | +window.electron.doThing() |
| 25 | +``` |
| 26 | + |
| 27 | +## Glossary |
| 28 | + |
| 29 | +### Main World |
| 30 | + |
| 31 | +The "Main World" is the javascript context that your main renderer code runs in. By default the page you load in your renderer |
| 32 | +executes code in this world. |
| 33 | + |
| 34 | +### Isolated World |
| 35 | + |
| 36 | +When `contextIsolation` is enabled in your `webPreferences` your `preload` scripts run in an "Isolated World". You can read more about |
| 37 | +context isolation and what it affects in the [BrowserWindow](browser-window.md) docs. |
| 38 | + |
| 39 | +## Methods |
| 40 | + |
| 41 | +The `contextBridge` module has the following methods: |
| 42 | + |
| 43 | +### `contextBridge.exposeInMainWorld(apiKey, api)` |
| 44 | + |
| 45 | +* `apiKey` String - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`. |
| 46 | +* `api` Record<String, any> - Your API object, more information on what this API can be and how it works is available below. |
| 47 | + |
| 48 | +## Usage |
| 49 | + |
| 50 | +### API Objects |
| 51 | + |
| 52 | +The `api` object provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api) must be an object |
| 53 | +whose keys are strings and values are a `Function`, `String`, `Number`, `Array`, `Boolean` or another nested object that meets the same conditions. |
| 54 | + |
| 55 | +`Function` values are proxied to the other context and all other values are **copied** and **frozen**. I.e. Any data / primitives sent in |
| 56 | +the API object become immutable and updates on either side of the bridge do not result in an update on the other side. |
| 57 | + |
| 58 | +An example of a complex API object is shown below. |
| 59 | + |
| 60 | +```javascript |
| 61 | +const { contextBridge } = require('electron') |
| 62 | + |
| 63 | +contextBridge.exposeInMainWorld( |
| 64 | + 'electron', |
| 65 | + { |
| 66 | + doThing: () => ipcRenderer.send('do-a-thing'), |
| 67 | + myPromises: [Promise.resolve(), Promise.reject(new Error('whoops'))], |
| 68 | + anAsyncFunction: async () => 123, |
| 69 | + data: { |
| 70 | + myFlags: ['a', 'b', 'c'], |
| 71 | + bootTime: 1234 |
| 72 | + }, |
| 73 | + nestedAPI: { |
| 74 | + evenDeeper: { |
| 75 | + youCanDoThisAsMuchAsYouWant: { |
| 76 | + fn: () => ({ |
| 77 | + returnData: 123 |
| 78 | + }) |
| 79 | + } |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | +) |
| 84 | +``` |
| 85 | + |
| 86 | +### API Functions |
| 87 | + |
| 88 | +`Function` values that you bind through the `contextBridge` are proxied through Electron to ensure that contexts remain isolated. This |
| 89 | +results in some key limitations that we've outlined below. |
| 90 | + |
| 91 | +#### Parameter / Error / Return Type support |
| 92 | + |
| 93 | +Because parameters, errors and return values are **copied** when they are sent over the bridge there are only certain types that can be used. |
| 94 | +At a high level if the type you want to use can be serialized and un-serialized into the same object it will work. A table of type support |
| 95 | +has been included below for completeness. |
| 96 | + |
| 97 | +| Type | Complexity | Parameter Support | Return Value Support | Limitations | |
| 98 | +| ---- | ---------- | ----------------- | -------------------- | ----------- | |
| 99 | +| `String` | Simple | ✅ | ✅ | N/A | |
| 100 | +| `Number` | Simple | ✅ | ✅ | N/A | |
| 101 | +| `Boolean` | Simple | ✅ | ✅ | N/A | |
| 102 | +| `Object` | Complex | ✅ | ✅ | Keys must be supported "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. | |
| 103 | +| `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type | |
| 104 | +| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context | |
| 105 | +| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are a the return value or exact parameter. Promises nested in arrays or obejcts will be dropped. | |
| 106 | +| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. | |
| 107 | +| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types | |
| 108 | +| `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped | |
| 109 | + |
| 110 | + |
| 111 | +If the type you care about is not in the above table it is probably not supported. |
0 commit comments