メインコンテンツへ飛ぶ

contextBridge

History

分離されたコンテキスト間に、安全、双方向で同期されたブリッジを作成します

プロセス: Renderer

分離されたプリロードスクリプトから API をレンダラーに公開する例を以下に示します。

// プリロード (隔離ワールド)
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// レンダラー (メインワールド)

window.electron.doThing()

用語集

メインワールド

"メインワールド" は、メインレンダラーコードが実行される JavaScript コンテキストです。 デフォルトでは、レンダラーでロードしたページはこのワールドでコードを実行します。

隔離ワールド

webPreferencescontextIsolation が有効 (これは Electron 12.0.0 からの既定の動作) になっている場合、preload スクリプトは "隔離ワールド" で実行されます。 コンテキスト分離とその影響の詳細については、BrowserWindow のドキュメントを参照してください。

メソッド

contextBridge モジュールには以下のメソッドがあります。

contextBridge.exposeInMainWorld(apiKey, api)

  • apiKey string - window に API を注入するキー。 その API には window[apiKey] でアクセスできます。
  • api Record - あなたの API です。この詳細と動作については下記を参照してください。

contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)

  • worldId Integer - API を注入するワールドの ID です。 0 はデフォルトのワールドで、999 は Electron の contextIsolation 機能で使用されるワールドです。 999 を使用すると、プリロードコンテキストのオブジェクトが公開されます。 隔離ワールドを作成する際には 1000 以上の使用を推奨します。
  • apiKey string - window に API を注入するキー。 その API には window[apiKey] でアクセスできます。
  • api Record - あなたの API です。この詳細と動作については下記を参照してください。

使い方

API

exposeInMainWorld に指定する api は、FunctionstringnumberArrayboolean、または文字列のキーで FunctionstringnumberArrayboolean、同じ条件を満たすオブジェクトのいずれかの値の、入れ子でなければなりません。

Function 値は他のコンテキストへプロキシされ、他のすべての値は コピー凍結 されます。 API で送信されるデータ/プリミティブはイミュータブルであり、ブリッジの一方で更新しても他方のものは更新されません。

複雑な API の例を以下に示します。

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

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing'),
myPromises: [Promise.resolve(), Promise.reject(new Error('whoops'))],
anAsyncFunction: async () => 123,
data: {
myFlags: ['a', 'b', 'c'],
bootTime: 1234
},
nestedAPI: {
evenDeeper: {
youCanDoThisAsMuchAsYouWant: {
fn: () => ({
returnData: 123
})
}
}
}
}
)

exposeInIsolatedWorld の例を以下に示します。

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

contextBridge.exposeInIsolatedWorld(
1004,
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// レンダラー (ワールド ID 1004 で隔離されています)

window.electron.doThing()

API 関数

contextBridge を介してバインドした Function 値は、コンテキストが分離されたままになるように Electron を介してプロキシされます。 これにより、以下に概説するいくつかの重要な制限が生じます。

引数 / エラー / 戻り値型のサポート

引数、エラー、戻り値は、ブリッジを介して送信されるときに コピー されるため、使用できるのは特定の型のみです。 高水準なものは、使用したい型をシリアライズおよびデシリアライズして、同じように動作するオブジェクトにできます。 以下の型サポートの表に全てが載っています。

種類複雑さ引数サポート戻り値サポート制限事項
文字列型単純なし
number単純なし
boolean単純なし
Object複雑キーにはこの表の "単純" な型のみの使用をサポートしています。 値にはこの表のものをサポートしています。 プロトタイプの変更は削除されます。 カスタムクラスを送信すると、値はコピーされますが、プロトタイプはコピーされません。
Array複雑制限は Object 型と同じです
エラー複雑送出された Error もコピーされるため、異なるコンテキストで投げられたためにエラーのメッセージやスタックトレースが少し変化することがあります。また、Error オブジェクトのカスタムプロパティは 失われます
Promise複雑なし
Function複雑プロトタイプの変更は削除されます。 クラスまたはコンストラクターを送信しても動作しません。
複製可能型単純複製可能型に関してはリンクのドキュメントを参照してください
Element複雑プロトタイプの変更は削除されます。 カスタム要素の送信は動作しません。
Blob複雑なし
SymbolなしSymbol はコンテキスト間でコピーできないため、削除されます

関心のある型が上記の表にない場合、それはおそらくサポートされていません。

Exposing ipcRenderer

Attempting to send the entire ipcRenderer module as an object over the contextBridge will result in an empty object on the receiving side of the bridge. Sending over ipcRenderer in full can let any code send any message, which is a security footgun. To interact through ipcRenderer, provide a safe wrapper like below:

// Preload (Isolated World)
contextBridge.exposeInMainWorld('electron', {
onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args))
})
// Renderer (Main World)
window.electron.onMyEventName(data => { /* ... */ })

Node のグローバルシンボルの公開

contextBridge はプリロードスクリプトで使用でき、レンダラーが Node API へアクセスできるようにします。 上記のサポート型の表は、 contextBridge を介して公開する Node API にも適用されます。 注意として、Node API の多くはローカルシステムのリソースへのアクセスを許してしまいます。 信頼できない外部コンテンツにおいては、公開するグローバルや API について注意が必要です。

const { contextBridge } = require('electron')
const crypto = require('node:crypto')
contextBridge.exposeInMainWorld('nodeCrypto', {
sha256sum (data) {
const hash = crypto.createHash('sha256')
hash.update(data)
return hash.digest('hex')
}
})