| [[Node.js]] | [[JavaScript]] | [[TypeScript]] | [[npm]] | [[Flutter]] | [[React]] |
==Electron==
{{amazon|B07QPQ24BN}}
*https://www.electronjs.org/
*[https://github.com/electron/electron-quick-start Quick Start]
===Fiddle===
----*[https://www.electronjs.org/fiddleエレクトロンを簡単に始める] ===API Document===----*https://www.electronjs.org/docs/api
===Required===
*[[Node.js]]のインストール
npm i --save-dev electron
</pre>
*グローバルにインストール[[npm]]<pre>npm -g i electron</pre> ====mainスクリプトファイルの作成package.json====
----
<pre>{ "name": "electron_sample", "version": "1.0.0", "main": "main.js", "scripts": { "start": "electron .", }, :}</pre> ====mainスクリプトファイル(main.js)の作成====----*mainスクリプトは、Electronアプリケーションのエントリーポイント(例えば,main。js)
*Mainプロセスを開始し、Mainプロセスはアプリケーションのライフサイクルをコントロールする
<pre>
function createWindow() {
const win = new BrowserWindow({
width:800400, height:600300,
webPreferences:{
preload: path.join(__dirname, 'preload.js')
})
</pre>
====Webページ(index.html)の作成====
----
<head>
<meta carhset="UTF-8">
<title>Electron Sample</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: white;">
<h1h2>Hello World!Version</h1h2> <pdiv> We are using Node.js <span id="node-version"></span>, </div> <div>
Chromium <span id="chrome-version"></span>,
</div> <div> and Electron <span id="electron-version"></span>. </pdiv>
</body>
</html>
</pre>
====プレロードスクリプト(preload.js)====
----
*Node.jsとWebページのブリッジ
*Node.js全体を安全に公開するのではなく、特定のAPIや動作をWebページに公開することができる*以下ではprocessオブジェクトからバージョン情報を読み取りページを更新する<pre>window.addEventListener('DOMContentLoaded', () => { const replaceText = (selector, text) => { const element = document.getElementById(selector); if (element) { element.innerText = text; } } for (const type of ['chrome', 'node', 'electron']) { replaceText(`${type}-version`, process.versions[type]) } })</pre>====.gitignore====----*https://github.com/electron/electron/blob/main/.gitignore ====起動====----<pre>npm start</pre> [[File:electron_sample_start.png|300px]] ====[[Visual Studio Code]]でのデバッグ====----*https://www.electronjs.org/docs/tutorial/debugging-vscodelaunch.json[https://www.typea.info/blog/index.php/2021/09/25/node_vscode_debug_globalinstall_module_can_not_loaded/ Node を Visual Studio Code でデバッグするときにグローバルにインストールしたモジュールが読み込まれない]<pre>{ "version": "0.2.0", "configurations": [ { "name": "Debug Main Process", "type": "node", "request": "launch", "cwd": "${workspaceFolder}", "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", "windows": { "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" }, "args" : ["."], "outputCapture": "std" } ]}</pre> ===Node ネイティブモジュール===----*https://www.electronjs.org/docs/tutorial/using-native-node-modules<blockquote>Node.jsのネイティブモジュールはElectronでサポートされていますが、Electronは特定のNode.jsのバイナリとは異なるアプリケーション・バイナリ・インターフェース(ABI)を持っているため(OpenSSLの代わりにChromiumのBoringSSLを使用するなどの違いがあるため)、使用するネイティブモジュールはElectron用に再コンパイルする必要があります。そうしないと、アプリを実行しようとしたときに、以下のクラスのエラーが発生します。</blockquote><pre>Error: The module '/path/to/native/module.node'was compiled against a different Node.js version usingNODE_MODULE_VERSION $XYZ. This version of Node.js requiresNODE_MODULE_VERSION $ABC. Please try re-compiling or re-installingthe module (for instance, using `npm rebuild` or `npm install`).</pre>====モジュールのインストール方法====----いくつかの方法がある=====インストールし、Electron向けにリビルド=====<blockquote>electron-rebuildパッケージを使ってElectron用にモジュールを再構築することができます。このモジュールは、Electronのバージョンを自動的に判断し、ヘッダーをダウンロードしてアプリ用のネイティブモジュールを再構築する手動ステップを処理することができます</blockquote><pre>npm install --save-dev electron-rebuild # Every time you run "npm install", run this:./node_modules/.bin/electron-rebuild # If you have trouble on Windows, try:.\node_modules\.bin\electron-rebuild.cmd</pre> ===パッケージングと配布===----====[https://www.npmjs.com/package/electron-packager electron-packager]====----*https://webbibouroku.com/Blog/Article/electron#outline__3<blockquote>Electron Packagerは、Electronベースのアプリケーションのソースコードを、リネームされたElectron実行ファイルおよびサポートファイルとともに、配布可能なフォルダにバンドルするコマンドラインツールおよびNode.jsライブラリです。</blockquote>*install**Globalインストールは非推奨<pre>npm install --save-dev electron-packager</pre>*コマンドラインからの使用<pre>npx electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch> [optional flags...]</pre>=====例([[Mac]])=====[[File:electron_package.png|500px]]<pre>$ npx electron-packager . </pre># プロジェクトディレクトリで $ npx electron-packager . を実行するだけ# {{プロジェクト}}-darwin-x64 配下に出力# Finderで確認# 実行できる=====例[[Windows]]=====[[File:electron_package_win.png|500px]]*[[Mac]]と同様の手順でOK ====[https://www.electronforge.io/ Electron Forge]====----*もっともシンプルで素早く配布するには、[https://www.electronforge.io/ Electron Forge]を利用する=====Electron ForgeをアプリケーションフォルダにImport=====<pre>$ npm install --save-dev @electron-forge/cl$ npx electron-forge import✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignore We have ATTEMPTED to convert your app to be in a format that electron-forge understands. Thanks for using "electron-forge"!!!</pre> =====[[Mac]] 配布パッケージを作成=====----*out フォルダに出力される<pre>$ npm run make > fx_sample@1.0.0 make> electron-forge make ✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64</pre> [[File:electron_forge_mac.png|400px]] *https://blog.ikappio.com/electron-forge-make-for-windows-from-macos/*ビルド環境と同じパッケージをデフォルトで生成するようだ。 =====[[Windows]]配布パッケージの作成=====----*[[Mac]] で [[Windows]]用のパッケージ出力には、monoなどインストールが必要なようなので、[[Windows]]同様の手順でパッケージを作成。 [[File:electron_forge_win.png|400px]] =====[[Ubuntu]]配布パッケージの作成=====----<pre>$ sudo apt install dpkg-dev$ sudo apt install rpm</pre> <pre>$ npm run make</pre>[[File:electron_forge_ubuntu.png|400px]] ==Electronの知識=====プロセス===----====メインプロセスとレンダラープロセス====----*main.js がメインプロセスを担い、GUIは持たない*レンダーラープロセスは、Electronに内臓のWebブラウザを利用する =====状況=====-----2021/10現在、contextBridge利用が推奨* nodeIntegration: true -> これで、Renderer 側で、Node api が使えていたが、今は使えない、remoteも使えない* nodeIntegration: false, contextIsolation: false -> これで、Main と Rendererで同一のコンテキストとなるので、windowにipcReaderを登録して使える* nodeIntegration: false, contextIsolation: true -> contextBridge を使うことで、IPC通信ができる(contextIsolation true必須 =====remoteオブジェクト=====----<blockquote>[https://simple-minds-think-alike.moritamorie.com/entry/disable-electron-remote-module 【Electron】remote moduleがdeprecatedになっている背景]</blockquote>*レンダラープロセスから、appやBrowserWindowなどのメインプロセス専用の機能を利用したい場合に用意されている*remoteは内部にまるでメインプロセスのモジュールが用意されているかのように振る舞う<pre>const { remote } = require('electron');</pre> ====IPC(プロセス間通信)====----*[https://qiita.com/hibara/items/c59fb6924610fc22a9db IPCについて]*メインプロセスとレンダラープロセスで情報を授受する場合、IPCを利用する*ページAからページBを操作したい場合など、メッセージを ページA->メインプロセス->ページBと連携させる必要がある =====ipcMain,ipcRenderer=====----[[File:electron_ipc.png|400px]]*main.js Window生成**preload.js ** contextIsolation: false<pre> let win = new BrowserWindow({ width: 600, height: 400, webPreferences:{ contextIsolation: false, // window object共有 preload: path.join(__dirname, 'preload.js') // nodeIntegration: true, // enableRemoteModule: true } }); // win.loadURL('https://service.typea.info/blogwiki'); win.loadFile('index.html');</pre>*main.js 通信<pre>const { ipcMain } = require('electron');ipcMain.handle('invoke-test', (ev, msg) => { console.log("Message From Renderer:" + msg); return "Main response!"; });</pre>*preload.js** contextIsolation: false, // window object共有 <pre>const { ipcRenderer } = require('electron');window.ipcRenderer = ipcRenderer;</pre>*index.html<pre> <script> ipcRenderer.invoke('invoke-test','sendmessage').then((data) => { console.log("Response from main:" + data); }); </script></pre>=====contextBridge=====----- *[https://qiita.com/pochman/items/64b34e9827866664d436 contextBridgeについて]*[https://blog.katsubemakito.net/nodejs/electron/ipc-for-contextbridge contextBridgeでのIPC]contextBridgeを使えば、nodeIntegration: false,contextIsolation: trueでもIPC通信できる*[https://www.electronjs.org/docs/tutorial/context-isolation contextIsolation]<blockquote>Context Isolationは、プリロードスクリプトとElectronの内部ロジックが、webContentsでロードするWebサイトとは別のコンテキストで実行されるようにする機能です。これは、WebサイトがElectronの内部やプリロードスクリプトがアクセスできる強力なAPIにアクセスできないようにするためのセキュリティ上の重要な機能です。 つまり、プリロードスクリプトがアクセスできるウィンドウオブジェクトは、実際にはWebサイトがアクセスできるオブジェクトとは異なるものです。例えば、プリロードスクリプトでwindow.hello = 'wave'と設定し、コンテキストアイソレーションを有効にした場合、ウェブサイトがwindow.helloにアクセスしようとすると、window.helloは未定義となります。 コンテキスト分離はElectron 12からデフォルトで有効になっており、すべてのアプリケーションで推奨されるセキュリティ設定です。</blockquote>*main.js Window生成**contextBridgeを使う場合、contextIsolation:true とする必要あり<pre> let win = new BrowserWindow({ width: 600, height: 400, webPreferences:{ contextIsolation: true, // false -> window object共有、contextBridge利用時はtrue preload: path.join(__dirname, 'preload.js'), // enableRemoteModule: false // nodeIntegration: true, } }); // win.loadURL('https://service.typea.info/blogwiki'); win.loadFile('index.html');</pre>*main.js 通信<pre>const { ipcMain } = require('electron');ipcMain.handle('invoke-test', (ev, msg) => { console.log("Message From Renderer:" + msg); return "Main response!"; });</pre>*preload.js<pre>const electron = require('electron');const { ipcRenderer, contextBridge } = electron; contextBridge.exposeInMainWorld( "api", { openWinWitMessage: (message) => { ipcRenderer.invoke('invoke-test', message).then((data) => { console.log("Response from main:" + data); }); } });</pre>*index.tml<pre> function openWinContextBridge() { window.api.openWinWitMessage("use contextBridge!!"); }</pre>[[file:electron_contextbridge.png|400px]] =====contextBridge(main から rendelerの呼び出し)=====-----*main.js*1秒ごとに時間を送信<pre> let win = new BrowserWindow({ width: 600, height: 400, webPreferences:{ preload: path.join(__dirname, 'preload.js'), } }); win.loadFile('index.html'); setInterval(() => { var now = new Date().toISOString(); console.log(now); win.webContents.send('timer', now); }, 1000);</pre>*preload.js<pre>const electron = require('electron');const { ipcRenderer, contextBridge /*remote*/ } = electron; contextBridge.exposeInMainWorld( "api", { on: (channel, callback) => { ipcRenderer.on(channel, (event, argv)=>callback(event, argv)) } });</pre>*index.html<pre> window.api.on('timer', (event, time)=>{ document.getElementById('timer').innerText = time; });</pre>[[file:electron_contextbridge_frommain.png|400px]] ==オブジェクト=====app===----*アプリケーション本体*起動/終了、Windowオープン/クローズなどの管理 ===BrowserWindow===----*Electronアプリで表示されるウィンドウオブジェクト*HTMLファイルを読み込むことでウィンドウを表示する===WebContents===----*BrowserWindowに含まれ、Webコンテンツの状態管理*Webコンテンツに関するイベント===BrowserView===----*BrowserWindowでloadFile、、loadURLを使って表示するコンテンツに、さらにWebコンテンツを埋め込む*BrowserWindow内部に小さな内部Windowのようなものを追加し、別コンテンツを表示できる<pre> const view = new BrowserView(); view.webContents .loadURL('https://service.typea.info/blogwiki'); win.setBrowserView(view); view.setBounds({ x : 100, y : 150, width : 300, height : 150 });</pre> [[File:electron_browser_view.png|400px]]===Menu===----*Menu,MenuItem*clickイベント<pre> let menu = new Menu(); let menuFile = new MenuItem({ label: 'ファイル', submenu: [ { label: '新規2', click: () => { console.log('新規2'); } }, new MenuItem({ label: '開く' }), new MenuItem({ label: '終了' }), ] }); menu.append(menuFile); Menu.setApplicationMenu(menu);</pre>[[File:electron_menu.png|300px]]====テンプレートからメニューを作成する====----* セパレータは、type: 'separator'<pre> let menuFileTemplate = [ { label: 'ファイル', submenu: [ { label: '新規2', click: () => { console.log('新規2'); } }, { label: '開く2' }, { type: 'separator' }, { label: '終了2' }, ] } ]; menu = Menu.buildFromTemplate(menuFileTemplate); Menu.setApplicationMenu(menu);</pre>====role====----*roleを指定するとロールの機能が組み込まれる**about**undo**redo**cut**copy**paste**pasteAndMatchStyle**selectAll**delete**minimize**close**quit**reload**forceReload**toggleDevTools**togglefullscreen**resetZoom**zoomIn**zoomOut**fileMenu**editMenu**viewMenu**windowMenu<pre> { label: '編集', submenu: [ { label: '切り取り', role: 'cut' }, { label: 'コピー', role: 'copy' }, { label: '貼り付け', role: 'paste' }, ] }</pre>[[File:electron_menu_role.png|300px]] ====コンテキストメニュー====----*contextBridgeを利用する[[File:electron_contextmenu.png|300px]] *index.html<pre> function openContextMenu(e) { e.preventDefault(); window.api.openContextMenu("hoge"); } window.addEventListener('contextmenu', openContextMenu, false);</pre>*preload.js<pre>contextBridge.exposeInMainWorld( "api", { openContextMenu: (type) => { return ipcRenderer.invoke('open-context-menu', type); } });</pre>*main.js<pre>const { ipcMain, BrowserWindow, Menu, dialog } = require('electron'); ipcMain.handle('open-context-menu', (ev, msg) => { var win = BrowserWindow.getFocusedWindow(); let contextmenuTemplate = [ { label: msg, click() { dialog.showMessageBox(win, {message : msg} ); } }, { type: 'separator' }, { label: '切り取り', role: 'cut' }, { label: 'コピー', role: 'copy' }, { label: '貼り付け', role: 'paste' }, ]; const contextMenu = Menu.buildFromTemplate(contextmenuTemplate); contextMenu.popup({window : win});});</pre> ===Dialog===----*https://www.electronjs.org/docs/api/dialog**showOpenDialogSync**showOpenDialog**showSaveDialogSync**showSaveDialog**showMessageBoxSync**showMessageBox**showErrorBox**showCertificateTrustDialog contextBridge を使用してファイル選択ダイアログを表示する*[https://www.electronjs.org/docs/api/browser-window BrowserWindow.getFocusedWindow()] で Windowハンドルを得る*main.js<pre>const { ipcMain, dialog } = require('electron');ipcMain.handle('open-file-dialog', async (ev, msg) => { var win = BrowserWindow.getFocusedWindow(); var result = await dialog.showOpenDialog(win, { properties: ['openFile', 'multiSelections'] }); if (result.canceld) { return []; } return result.filePaths;});</pre>*preload.js<pre>const electron = require('electron');const { ipcRenderer, contextBridge } = electron; contextBridge.exposeInMainWorld( "api", { openFileDialog: (message) => { return ipcRenderer.invoke('open-file-dialog', message); } });</pre>*index.html<pre> async function openWinFileDialog() { var filePaths = await window.api.openFileDialog(""); alert(filePaths[0]); }</pre> ==構成=====main.js===----<pre>const { app, BrowserWindow} = require('electron'); function createWindow() { let win = new BrowserWindow({ width: 400, height: 200, webPreferences:{ contextIsolation: false, // window object共有 preload: path.join(__dirname, 'preload.js') // nodeIntegration: true, // enableRemoteModule: true } }); win.loadFile('index.html');} app.whenReady().then(createWindow);</pre>====オブジェクトの分割代入====---- const { app, BrowserWindow} = require('electron');====Preloadスクリプト====----*https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts '''プリロードスクリプトには、ウェブコンテンツの読み込み開始前にレンダラープロセスで実行されるコードが含まれています。これらのスクリプトはレンダラーのコンテキスト内で実行されますが、Node.jsのAPIにアクセスできるため、より多くの権限が与えられています。''' ====[[Node.js]]機能の統合====----*trueで[[Node.js]]の機能(通常のWebで使用できないrequireなど)を利用できるようになる nodeIntegration: true ====remoteモジュールの有効化====----*remoteモジュールの有効化 enableRemoteModule: true *https://www.electronjs.org/docs/tutorial/security**Do not enable Node.js Integration for Remote Content '''リモートコンテンツを読み込むレンダラー(BrowserWindow、BrowserView、<webview>)では、Node.jsの統合を有効にしないことが最も重要です。この目的は、リモートコンテンツに与える権限を制限することで、攻撃者がウェブサイト上でJavaScriptを実行できるようになった場合に、ユーザーに危害を加えることを劇的に難しくすることです。 この後、特定のホストに対して追加の権限を付与することができます。例えば、https://example.com/ に向けてBrowserWindowを開いている場合、そのWebサイトが必要とする能力を正確に与えることができますが、それ以上はできません。''' ====Webページをロード====----*loadURLとすることで、外部ページをロードできる<pre> // win.loadFile('index.html'); win.loadURL('https://service.typea.info/blogwiki'); </pre>*[https://service.typea.info/blogwiki Webページ]をElectronアプリ化[[File:electron_web_app.png|500px]] ====モーダルダイアログ====----<pre>function createWindow() { let win = new BrowserWindow({ width: 600, height: 400, webPreference: { nodeIntegration: true, enableRemoteModule } }); // win.loadURL('https://service.typea.info/blogwiki'); win.loadFile('index.html'); let child = new BrowserWindow({ width: 400, height: 200, parent: win, frame: false, modal: true, transparent: true, opacity: 0.5 }); child.loadFile('dialog.html');}</pre>[[File:electron_modal_dialog.png|400px]] ====デベロッパーツールを開く====---- win.webContents.openDevTools();[[File:electron_devtools.png|400px]] ==appオブジェクトのイベント=====起動処理の完了===will-finish-launching===初期化処理完了===ready===BrowserWindowの生成===browser-window-created===Webコンテンツの生成===web-contents-created===全てのWindowが閉じられた===window-all-closed===全てのWindowを閉じる前===before-quit===終了する前===will-quit===終了時===quit==BrowserWindowのイベント=====Windowの表示===show ===Windowの非表示===hide ===Window表示準備完了===ready-to-show ===Windowを閉じる===close ===Windowが閉じられた===closed===その他===*focus*blur*maximize*unmaximize*minimize*restore*will-resize*resize*will-move*move*enter-full-screen*leave-full-screen*enter-html-full-screen*leave-html-full-screen*always-on-top-changed==BrowseWindow操作==*destory*close()*focus()*blur()*isFocuced()*isDestoryed()*show()*showInactive()*hide()*isVisible()*isModal()*maximize()*unmaximize()*isMaximized()*minimize()*restore*isMinimized()*setFullScreen()*isFullScreen()*isNormal()*SetBounds()*GetBounds()*SetContentBounds()*GetContentsBound()*SetSize()*GetSize()*SetContaentSize()*GetContentSize()*SetMinimumSize()*GetMinimumSize*SetMaximumSize()*GetMaximumSize()*SetPosition()*GetPosition()*moveTop()*center()*settitle()*getTitle() ==WebContentsのイベント=====コンテンツロード完了===did-finish-load ===フレームのコンテンツロード===did-frame-finish-load===コンテンツ読み込み開始===did-start-loading===コンテンツ読み込み中止===did-stop-loading===DOM生成完了===dom-ready===新しいWindow作成===new-window===URLアクセス時===will-navigate===URLアクセス開始===did-start-navigation===その他===*will-redirect*did-redirect-navigation*did-navigate*will-prevent-unload*destroyed*enter-html-full-screen*leave-html-full-screen*zoom-changed*devtools-opend*devtools-closed*devtools-focused*console-message==Tips=====ファイルを開く===----*コンテキストメニューからファイルを開くダイアログで選択したファイルを画面に表示*main.js<pre>ipcMain.handle('open-context-menu', (ev, msg) => { var win = BrowserWindow.getFocusedWindow(); let contextmenuTemplate = [ { label: 'ファイルを開く', click() { openFile(win); } } ]; const contextMenu = Menu.buildFromTemplate(contextmenuTemplate); contextMenu.popup({window : win});}); async function openFile(win) { var result = await dialog.showOpenDialogSync( win, { properties: ['openFile'], filters: [ {name:'text', extensions: ['txt'] }, {name:'all', extensions: ['*'] }, ] }); if (result.canceld) { return; } var filePath = result[0]; var content = fs.readFileSync(filePath).toString(); win.webContents.send('open-file', content);}</pre>*preload.js<pre>contextBridge.exposeInMainWorld( "api", { openContextMenu: (type) => { return ipcRenderer.invoke('open-context-menu', type); }, on: (channel, callback) => { ipcRenderer.on(channel, (event, argv)=>callback(event, argv)) } });</pre>*index.html<pre> window.addEventListener('contextmenu', openContextMenu, false); window.api.on('open-file', (event, content)=>{ document.getElementById('open_file').value = content; });</pre> ===ファイルを保存===----*main.js<pre>const { ipcMain, app, BrowserWindow, Menu, MenuItem, dialog } = require('electron');const fs = require('fs'); ipcMain.handle('open-context-menu', (ev, msg) => { var win = BrowserWindow.getFocusedWindow(); let contextmenuTemplate = [ { label: 'ファイルを保存', click() { saveFile(win); } }, ]; async function saveFile(win) { var result = await dialog.showSaveDialogSync( win, { properties: [''] }); if (result.canceld) { return; } var filePath = result; var data = await win.webContents.executeJavaScript('window.document.getElementById("open_file").value'); fs.writeFileSync(filePath, data);}</pre>*index.html<pre> <textarea id="open_file" rows="10" cols="80"></textarea> : function openContextMenu(e) { e.preventDefault(); window.api.openContextMenu("hoge"); } window.addEventListener('contextmenu', openContextMenu, false);</pre> ===httpを用いてデータを取得===----[[File:electron_http_get.png|400px]]*Node の https パッケージでは使い勝手が割るので、superagent を導入<pre>$ npm install --save superagent</pre>*index.html<pre> <textarea id="open_file" rows="10" cols="80"></textarea> <input type="text" id="getHttpDataUrl" value="https://www.typea.info/blog/index.php/feed/" /> <input type="button" id="btnGetHttpData" value="get http data" /> : async function getHttpData() { var data = await window.api.getHttpData(document.getElementById('getHttpDataUrl').value); document.getElementById("open_file").value = data; } document.getElementById("btnGetHttpData").addEventListener('click', getHttpData); </pre>*preload.js<pre>contextBridge.exposeInMainWorld( "api", { getHttpData: (url) => { return ipcRenderer.invoke('get-http-data', url); }, });</pre>*main.js<pre>ipcMain.handle('get-http-data', async (ev, url) =>{ // https://www.typea.info/blog/index.php/2017/08/19/react_react_router_redux-saga_ajax/ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // 開発用証明書エラー無視 var response = await request.get(url).query().buffer(); console.log(response); return response.res.text;});</pre>===sqlite===----*https://www.virment.com/use-sqlite3-electron-vue-js/[[File:electron_sqlite3.png|400px]]<pre>$ npm install --save-dev electron-rebuild$ npm install --save sqlite3$ ./node_modules/.bin/electron-rebuild -f -w sqlite3</pre> *main.js<pre>const sqlite3 = require('sqlite3'); : var db = new sqlite3.Database(filePath); db.serialize(() => { db.run("create table if not exists test(id int primary key, value text)"); }); db.close();</pre>