【保存版】Electronでプリロードスクリプトを使いこなす!nodeIntegration設定不要でモジュールを安全に読み込む方法
Electron で「require() is not defined」エラーを解決する方法
Electron アプリケーション開発において、レンダラープロセスで require()
関数を使用しようとすると、ReferenceError: require is not defined
エラーが発生することがあります。これは、Electron v12 以降でレンダラープロセスでデフォルトで Node.js API が無効化されているためです。
解決策
この問題を解決するには、以下のいずれかの方法を使用する必要があります。
preload.js
ファイルは、レンダラープロセスとメインプロセスの間で通信するためのブリッジとして機能します。このファイルを使用して、require()
関数を含む必要な Node.js API をレンダラープロセスに提供することができます。
手順
preload.js
ファイルを作成します。preload.js
ファイル内で、必要な Node.js モジュールをrequire()
します。contextBridge.exposeInMainWorld()
API を使用して、レンダラープロセスに Node.js API を公開します。webPreferences
オプションでpreload
プロパティを使用して、preload.js
ファイルのパスを設定します。
例
// preload.js
const { remote } = require('electron');
contextBridge.exposeInMainWorld('electron', remote);
// main.js
const { app, BrowserWindow } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
});
win.loadFile('index.html');
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
contextBridge
API は、Electron v17 以降で導入された新しい API です。この API を使用して、レンダラープロセスに特定の Node.js API を選択的に公開することができます。
contextBridge
API をインポートします。webPreferences
オプションでcontextIsolation
プロパティをtrue
に設定します。
// renderer.js
import { contextBridge } from 'electron';
const { remote } = contextBridge.exposeInMainWorld('electron');
// main.js
const { app, BrowserWindow } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
contextIsolation: true,
},
});
win.loadFile('index.html');
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
メインプロセスからレンダラープロセスにメッセージを送信し、レンダラープロセス側で Node.js API を呼び出す方法もあります。
ipcRenderer
API を使用して、レンダラープロセスにメッセージを送信します。- レンダラープロセスで
ipcMain
API を使用して、メインプロセスからのメッセージを受信します。 - 受信したメッセージに基づいて、必要な Node.js API を呼び出します。
// main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
contextIsolation: true,
},
});
win.loadFile('index.html');
ipcMain.on('require-node-api', (event, apiName, args) => {
const result = require(apiName)(...args);
event.reply('node-api-result', result);
});
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
Electron で「require() is not defined」エラーを解決するサンプルコード
preload.js ファイルを使用する
preload.js
const { contextBridge } = require('electron');
const fs = require('fs');
contextBridge.exposeInMainWorld('fs', {
readFileSync: fs.readFileSync,
});
main.js
const { app, BrowserWindow } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
});
win.loadFile('index.html');
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
index.html
<!DOCTYPE html>
<html>
<head>
<title>Electron Preload Demo</title>
</head>
<body>
<script>
const fs = window.require('fs');
const content = fs.readFileSync('data.txt', 'utf8');
console.log(content);
</script>
</body>
</html>
contextBridge API を使用する
この例では、contextBridge
API を使用して、特定の Node.js API をレンダラープロセスに公開する方法を示します。
renderer.js
import { contextBridge } from 'electron';
const { fs } = contextBridge.exposeInMainWorld('electron', {
fs: {
readFileSync: require('fs').readFileSync,
},
});
window.addEventListener('DOMContentLoaded', () => {
const content = fs.readFileSync('data.txt', 'utf8');
console.log(content);
});
const { app, BrowserWindow } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
contextIsolation: true,
},
});
win.loadFile('index.html');
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
メインプロセスからレンダラープロセスにメッセージを送信する
const { app, BrowserWindow, ipcMain } = require('electron');
const fs = require('fs');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
contextIsolation: true,
},
});
win.loadFile('index.html');
ipcMain.on('require-fs-api', (event, fileName) => {
const content = fs.readFileSync(fileName, 'utf8');
event.reply('fs-api-result', content);
});
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
<!DOCTYPE html>
<html>
<head>
<title>Electron IPC Demo</title>
</head>
<body>
<button onclick="readFile('data.txt')">Read File</button>
<script>
const { ipcRenderer } = require('electron');
function readFile(fileName) {
ipcRenderer.send('require-fs-api', fileName);
ipcRenderer.on('fs-api-result', (event, content) => {
console.log(content);
});
}
</script>
</body>
</html>
これらのサンプルコードはあくまでも一例であり、状況に合わせて変更する必要があります。
Electron で「require() is not defined」エラーを解決するその他の方法
remote
モジュールは、Electron v12 以前で使用されていた方法です。このモジュールを使用すると、レンダラープロセスからメインプロセスのすべての Node.js API にアクセスすることができます。
remote
モジュールをインポートします。
// renderer.js
const { remote } = require('electron');
const fs = remote.require('fs');
const content = fs.readFileSync('data.txt', 'utf8');
console.log(content);
注意事項
remote
モジュールは、セキュリティ上の理由から Electron v17 で非推奨になりました。remote
モジュールを使用する場合は、セキュリティ対策を十分に行う必要があります。
Browserify または Webpack などのツールを使用して、Node.js モジュールをバンドルすることができます。バンドルされたモジュールは、レンダラープロセスで直接使用することができます。
- Browserify または Webpack をインストールします。
- バンドルする Node.js モジュールを指定します。
- バンドルされたモジュールの出力ファイルを作成します。
- バンドルされたモジュールの出力ファイルを HTML ファイルにインポートします。
package.json
{
"devDependencies": {
"browserify": "^17.0.0",
"electron": "^17.0.0"
}
}
const { app, BrowserWindow } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
},
});
win.loadFile('index.html');
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
<!DOCTYPE html>
<html>
<head>
<title>Electron Browserify Demo</title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
browserify.config.js
const browserify = require('browserify');
const fs = require('fs');
const b = browserify('./renderer.js');
b.bundle().pipe(fs.createWriteStream('bundle.js'));
const fs = require('fs');
const content = fs.readFileSync('data.txt', 'utf8');
console.log(content);
taurine.js は、Electron アプリケーションを WebAssembly で実行できるようにするライブラリです。taurine.js を使用すると、レンダラープロセスで Node.js API を直接使用することができます。
- taurine.js をインストールします。
- taurine.js を使用して Electron アプリケーションをビルドします。
{
"devDependencies": {
"taurine.js": "^1.0.0"
}
}
taurine.config.json
{
"app": "index.html",
"webBundle": {
"includeNodejs": true
}
}
<!DOCTYPE html>
<html>
<head>
<title>Electron Taurine.js Demo</title>
</head>
<body>
<script>
const fs = require('fs');
const content = fs.readFileSync('data.txt', 'utf8');
console.log(content);
</script>
</body>
</html>
javascript html node.js