プリロードスクリプトの利用
これは Electron チュートリアルの 3 章 です。
学習目標
このチュートリアルでは、プリロードスクリプトとは何か、そしてプリロードスクリプトを使用して特権 API を安全にレンダラープロセスへ公開する方法について学びます。 また Electron のプロセス間通信 (IPC) モジュールを用いた、メインプロセスとレンダラープロセス間の通信方法についても学びます。
プリロードスクリプトとは何でしょう?
Electron のメインプロセスは、オペレーティングシステムにフルアクセス可能な Node.js 環境です。 On top of Electron modules, you can also access Node.js built-ins, as well as any packages installed via npm. 一方、レンダラープロセスはウェブページを実行するもので、セキュリティ上の理由からデフォルトでは Node.js を実行しません。
Electron の異なる種類のプロセスをブリッジするために、プリロード と呼ばれる特別なスクリプトを使用する必要があります。
プリロードスクリプトを使ってレンダラーを拡張する
BrowserWindow のプリロードスクリプトは、HTML DOM に加えて Node.js と Electron API の制限付きサブセットの両方にアクセスできるコンテキストで実行されます。
Electron 20 以降、プリロードスクリプトはデフォルトで サンドボックス化 され、完全な Node.js 環境にはアクセスできなくなりました。 実際には、限られた API のあつまりのみにアクセスできる、ポリフィルされた require
関数があるということです。
利用可能な API | 詳細 |
---|---|
Electron モジュール | レンダラープロセスのモジュール |
Node.js モジュール | events , timers , url |
ポリフィルされたグローバル | Buffer , process , clearImmediate , setImmediate |
For more information, check out the Process Sandboxing guide.
プリロードスクリプトは、Chrome 拡張機能の コンテンツスクリプト と同様の、レンダラーがウェブページを読み込む前に注入されるスクリプトです。 To add features to your renderer that require privileged access, you can define global objects through the contextBridge API.
このコンセプトを実証するために、アプリの Chrome、Node、Electron のバージョンをレンダラーへ公開するプリロードスクリプトを作成します。
新しく preload.js
スクリプトを追加し、ここでは Electron の process.versions
オブジェクトから選んだプロパティをレンダラープロセスでの versions
グローバル変数へと公開します。
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron
// 関数だけでなく変数も公開できます
})
このスクリプトをレンダラープロセスへアタッチするには、BrowserWindow のコンストラクタの webPreferences.preload
オプションにそのパスを渡します。
const { app, BrowserWindow } = require('electron')
const path = require('node:path')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
これによりレンダラーは versions
グローバルにアクセスできますので、その情報をウインドウに表示させましょう。 この変数は window.versions
または単に versions
でアクセスできます。 renderer.js
スクリプトを作成し、これで document.getElementById
DOM API を使用して id
プロパティが info
である HTML 要素の表示テキストを置換します。
const information = document.getElementById('info')
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`
そして index.html
は、id
プロパティが info
である要素を新規追加し、renderer.js
スクリプトをアタッチするように変更します。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
</body>
<script src="./renderer.js"></script>
</html>
上記のステップを踏むと、アプリは以下のような外観になるでしょう。
そしてコードは以下のようになります。
- main.js
- preload.js
- index.html
- renderer.js
const { app, BrowserWindow } = require('electron/main')
const path = require('node:path')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
const { contextBridge } = require('electron/renderer')
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
</body>
<script src="./renderer.js"></script>
</html>
const information = document.getElementById('info')
information.innerText = `This app is using Chrome (v${window.versions.chrome()}), Node.js (v${window.versions.node()}), and Electron (v${window.versions.electron()})`