Electron: 反応中の電子のインポート中にエラーが発生しました| 'electron'から{ipcRenderer}をインポートします

作成日 2017年07月03日  ·  65コメント  ·  ソース: electron/electron

create-react-appを使用して単純なreactアプリを作成し、それを電子と正常に統合しました。 アクションクリエーターファイル内に電子をインポートしようとするまで、すべてがうまく機能していました。 下の行を削除すると、アプリは正常に動作します。 問題は、ipcRendererを使用して反応側から電子メインプロセスに通信できないことです。

この行により、アプリがクラッシュします。
import { ipcRenderer } from 'electron';

次のエラーが発生します。

TypeError:fs.​​existsSyncは関数ではありません
(無名関数)
node_modules / electronic / index.js:6

  3 | 
  4 | var pathFile = path.join(__dirname, 'path.txt')
  5 | 
> 6 | if (fs.existsSync(pathFile)) {
  7 |   module.exports = path.join(__dirname, fs.readFileSync(pathFile, 'utf-8'))
  8 | } else {
  9 |   throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')

私はグーグルでこれが電子を輸入しようとするときの一般的な問題であることを知りました。

助けてくれてありがとう

最も参考になるコメント

@MarshallOfSound私の間違い。

それが誰かを助けることができるならば、私は問題#7300で解決策を見つけました。

const { ipcRenderer } = window.require('electron');

これはElectronアプリを実行するときに機能することに注意してください。ただし、ブラウザー内でReactコードをテストするだけの場合は、クラッシュします(window.requireは、Electronのようにブラウザーで定義されていません)。

全てのコメント65件

CRAは、標準のモジュール読み込み(fsを含む)を台無しにするwebpackを使用します。

webpackのElectronモードを調べて、CRAから排出することをお勧めします

GitHubの問題は、機能のリクエストとバグレポートに関するものです。Electronの使用に関する質問は、コミュニティまたはSlackChannelに送信する必要があります。

@MarshallOfSound私の間違い。

それが誰かを助けることができるならば、私は問題#7300で解決策を見つけました。

const { ipcRenderer } = window.require('electron');

これはElectronアプリを実行するときに機能することに注意してください。ただし、ブラウザー内でReactコードをテストするだけの場合は、クラッシュします(window.requireは、Electronのようにブラウザーで定義されていません)。

app.quit()にアクセスする場合は、次を使用できます。

const {app} = window.require( 'electron')。remote;

多分それは誰かを助けます...

@CiriousJokerこれらは解決策です、ありがとう!

まだwindow.require is not a functionます。 Electron with React Starter Kit(https://github.com/kriasoft/react-starter-kit)を使用しています。 これを除いて、すべてがうまく機能しています。

ElectronアプリをWebからロードするように設定したため、アプリはローカルで実行されていません。
https://gist.github.com/holgersindbaek/68f6db82f507967a51ca75c527faeff6

私がやろうとしているのは、私のReactファイルの1つでipcRendererを呼び出すことです。 ただし、アプリがWebから読み込まれている場合でも、それが可能かどうかはわかりません。 助言がありますか?

@holgersindbaek

あなたと同じ船で...あなたは解決策を見つけましたか?

いいえ。ブラウザからipcRendererをロードすることはできないと確信しています。

ブラウザでReactアプリを実行している場合、それは機能しません。 Electron内で実行すると、問題ないはずです。

@Amthieuアドバイスありがとうございます。 Reactプロジェクト(React Starter Kitに基づく)をElectronで実行する方法についてはまだ疑問があります。 任意のアドバイスをいただければ幸いです。

https://discuss.atom.io/t/getting-electron-to-work-with-react-starter-kit/48594

そうです、私には解決策があります。

1)次のコードでpreload.js fileを作成します。

window.ipcRenderer = require('electron').ipcRenderer;

2) webPreferences介してこのファイルをmain.jsにプリロードします:

  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      preload: __dirname + '/preload.js'
    }
  });

3)これで、reactアプリからアクセスできるようになります。 たとえば、これは機能します:

componentDidMount() {
        if (isElectron()) {
            console.log(window.ipcRenderer);
            window.ipcRenderer.on('pong', (event, arg) => {
                this.setState({ipc: true})
            })
            window.ipcRenderer.send('ping')
        }
    }

注-これを使用する: isElectron()関数のhttps://github.com/cheton/is-electron

@HemalRステップ3は次のようになります(現在):

componentDidMount() {
    if (window.isElectron) {
        console.log(window.ipcRenderer);
        window.ipcRenderer.on('pong', (event, arg) => {
            this.setState({ipc: true})
        })
        window.ipcRenderer.send('ping')
    }
}

window.isElectronは関数ではありません。

@ nparsons08

謝罪-isElectronを取得している場所に追加する必要があり、次のリンクを使用してコード例を編集しました: https

@holgersindbaek
今解決策はありますか

私にとっては、 nodeIntegrationtrue場合にのみ機能します。

webPreferences: {
      nodeIntegration: true, 
      preload: __dirname + '/preload.js'
}

@HemalRソリューションで

今、FROM電子をReactに送る方法は?

で試した
電子側

 ipcMain.emit("pong", "Hello!"); 

しかし、Reactリスナーからは何も受信されませんでした

window.ipcRenderer.on("pong", (event, arg) => {
        console.log("PONG");
});

ipcMain.emit()を使用するのは正しいですか、それとも他のものを使用する必要がありますか?

わかりました、私は(電子メインプロセスで)使用する必要があることがわかりました

mainWindow.webContents.send("pong", "Hello!");

皆さんありがとうございます!

私は上記のすべてを無駄に試しました。 私のために働いたのは巨大なハックでした。 ファイル./node_modules/electron/index.jsを変更し、パスをelectron.exeハードコーディングします

例えば

function getElectronPath() {
  return 'D:\\Repos\\MyProject\\node_modules\\electron\\dist\\electron.exe';
}

module.exports = getElectronPath();

うわー、私はIPCendererを私のReactコンポーネントで動作させることができませんでした。 上記のすべての方法を試しました。 ちなみに、それが機能するために使用できるヒントはありましたか? ありがとう

うーん...私のelectronアプリは、上記のソリューションを使用しても問題なく動作しますが、数か月間更新していません(更新する必要はありません)。

これが機能しなくなるような重大な変更があるのだろうか? たぶんあなたたちはあなたの電子バージョンを投稿することができますか?

@cyclonstepあなたが得ていた特定のエラーはありますか? コードスニペットまたはいくつかのログなしで助けるのは難しい...

束ねるのに小包を使っています。
Window.requireも私のためにそれを解決しました(また、何が解決しなかったかを示しています):

'vue / dist /vue.min'からVueをインポートします
'./App'からアプリをインポートします

// 悪い? 'electron'から{ipcRenderer}をインポートします
// 悪い? const {ipcRenderer} = require( 'electron')
// 良い:
const {ipcRenderer} = window.require( 'electron')

(同じファイルのさらに下にあるのは、電子のポンデモ

おそらく注目に値する:それを間違えたとしても、バンドルサイズはエレクトロンサイズ全体などで大きくなることはありません(電子を必要としない場合と比較してください。これはこれまでのところ、レンダリング側の電子インポートのみです)が、約20kbしかありません、それ自体はいくつかのシム/ラッパーコードのようで、 node_modules/electron-download/node_modules/debug/dist/debug.js :242:ff ..から来ています。

2: [function (require, module, exports) {
  // shim for using process in browser
  var process = module.exports = {}; // cached from whatever global is present so that test runners that
 stub it

とにかく、物事は上記のように機能します。

ノードバージョン10.2.0
Chromeバージョン66.0.3359.181
Electronバージョン3.0.2

window.requireがメインスクリプトでエラーwindow is not definedで機能していなかったため、 const electron = eval('require')("electron")に切り替えました。 これが誰かを助けることを願っています。 webpackを使用していて、問題はwebpackがコンパイル時にrequireステートメントを評価していたことでした。

@MarshallOfSound私の間違い。

それが誰かを助けることができるならば、私は問題#7300で解決策を見つけました。

const { ipcRenderer } = window.require('electron');

これはElectronアプリを実行するときに機能することに注意してください。ただし、ブラウザー内でReactコードをテストするだけの場合は、クラッシュします(window.requireは、Electronのようにブラウザーで定義されていません)。

そしてtypescriptの場合:

import {IpcRenderer} from 'electron';

declare global {
  interface Window {
    require: (module: 'electron') => {
      ipcRenderer: IpcRenderer
    };
  }
}

const { ipcRenderer } = window.require('electron');

@moshfeuあなたのソリューションは素晴らしい働きをします。 ReactプロジェクトでIpcRendererを使用するのにWebpackやBrowserfyは必要ありません。 どうもありがとうございました:D

タイプスクリプトの場合、上記の@HemalRの例を使用しますが、 nodeIntegration: trueません: https

そうです、私には解決策があります。

  1. 次のコードでpreload.js fileを作成します。
window.ipcRenderer = require('electron').ipcRenderer;
  1. webPreferences介してこのファイルをmain.jsにプリロードします:
  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      preload: __dirname + '/preload.js'
    }
  });
  1. これで、reactアプリからアクセスできるようになります。 たとえば、これは機能します:
componentDidMount() {
      if (isElectron()) {
          console.log(window.ipcRenderer);
          window.ipcRenderer.on('pong', (event, arg) => {
              this.setState({ipc: true})
          })
          window.ipcRenderer.send('ping')
      }
  }

注-これを使用する: isElectron()関数のhttps://github.com/cheton/is-electron

と組み合わせ
https://github.com/electron/electron/issues/9920#issuecomment -447157348

私はこれを使用しました:

import { IpcRenderer } from 'electron';

declare global {
  interface Window {
    ipcRenderer: IpcRenderer
  }
}

export const { ipcRenderer } = window;

それが誰かを助けてくれることを願っています! stenciljsで動作し、反応と角度を想像します

webpackの設定にターゲット「electron-renderer」を追加するだけです。
デフォルトのエクスポート{
..。
ターゲット:「エレクトロンレンダラー」
..。
}

こんにちは、私はCRA + Electronを使用しています。 そして、ターゲット「electron-renderer」によってプロジェクトを構築します。 ビルドフォルダにファイルをロードしている間はうまく機能しますが、URL localhost:3000を開発してロードするとエラーが発生します。 その理由は、reactコンポーネントでノードAPIと電子APIを使用しているためだと思います。 誰かが解決策を持っていますか? ありがとう。

TypeError: fs.existsSync is not a function

ええ、 fs apiはブラウザで利用できません。 私が状況を正しく理解している場合は、 react-scripts start (CRAのnpm startのデフォルトスクリプト)を使用してアプリを実行します。

これを行う正しい方法は、 electron .を実行することです。 あなたはそれをドキュメントで見ることができます: https

それがあなたのために働くならばLMK。 また、私のアプリでどのように機能するかを確認できます-https://github.com/moshfeu/y2mp3 (CRAで作成されていないことに注意して

こんにちは、私はCRA + Electronを使用しています。 そして、ターゲット「electron-renderer」によってプロジェクトを構築します。 ビルドフォルダにファイルをロードしている間はうまく機能しますが、URL localhost:3000を開発してロードするとエラーが発生します。 その理由は、reactコンポーネントでノードAPIと電子APIを使用しているためだと思います。 誰かが解決策を持っていますか? ありがとう。

TypeError: fs.existsSync is not a function

webpackの設定にターゲット「electron-renderer」を追加するだけです。
デフォルトのエクスポート{
..。
ターゲット:「エレクトロンレンダラー」
..。
}

それは私にとってもうまくいきます。

これが私のツールバージョンです:

  • webpack: "3.8.1"
  • 電子:「4.2.1」

electron-rendererは、この電子の問題を解決するためだけのものだと思います。 window.requiredような有線構文を使用する必要はなく、入力もできなくなりました。

私の場合、ターゲットの設定に取り組みました:webpackとnodeIntegrationの「electron-rendering」:BrowserWindowオプションでtrue
今日の最後のバージョンのwebpack + electronic + reactを使用しています

TypeScript anElectronでcreate-react-appを実行しています。 私はセットアップのためにこれらの非常に良い指示に従いました。 しかし、それから私もこのエラーに遭遇しました。 私のために働く解決策は、このスレッドで言われていることの合計です:

  1. react-scriptで"electron-renderer"targetとして使用するようにします。 これにはrescriptsrescript-envを使用します。

package.json

  "rescripts": [
    "env"
  ],

.rescriptsrc.js

module.exports = [require.resolve( "./ webpack.config.js")];

webpack.config.js

module.exports = config => {
  config.target = "electron-renderer";
  return config;
};
  1. nodeIntegrationを追加します
new BrowserWindow({
  webPreferences: {
    nodeIntegration: true
  }
});
  1. src/typings.d.tsを追加します:
declare var window: Window;
interface Window {
  require: any;
}

そしてついにあなたのアプリでtheeeen

App.tsx

const { remote } = window.require("electron");
console.log(remote.getCurrentWindow());

@LukasBombach
これも機能するはずです:

declare var window: Window;
interface Window {
  require: NodeRequire
}

次に、必要な定数を入力します

ありがとう!

他の人に役立つ場合に備えて、Vueに使用した手順は次のとおりです。

ブラウザウィンドウを作成するときにノード統合をWeb設定に追加して、レンダラープロセスでノード統合が有効になっていることを確認します。

new BrowserWindow({
    webPreferences: {
        nodeIntegration: true,
    },
})
````

Configure webpack to package your application for electron renderer by adding a target to your `vue.config.js` (or wherever you set your vue settings). 
```js
module.exports = {
    configureWebpack: {
        target: 'electron-renderer',
    },
}

アプリケーション内に必要なものをインポートします。 次のように、シェルモジュールをコンポーネントにインポートしています。

import { shell } from 'electron'

まだ同じ問題を抱えている人に。 これは私がこれまでに見つけた最良の解決策です

`` `js
new BrowserWindow({
webPreferences:{
nodeIntegration:true
}
});

多くの人があなたのアプリにfsまたはipcRendererをインポートすることについて質問しているので、このコメントが注目されることを願っています。 これは電子アプリの一般的なニーズですが、多くの人がそれを正しく理解しておらず、時代遅れのパターンを使用していることがわかりました。 tl; dr-ノードモジュール(つまりfs )または電子モジュール(つまりipcRenderer )を正しい方法でインポートしないと、セキュリティの脆弱性があります。 自分だけのためにアプリを使用している場合は、おそらく安全ですが、アプリを共有または販売したい場合は、事前に読んでおく必要があります。

私たちの目標

ソリューションに入る前に、そもそもなぜこれを行っているのかを理解することが重要です。 Electronアプリを使用すると、ノードモジュールをアプリに含めることができます。これにより、驚くべきパワーが得られますが、セキュリティ上の懸念があります。 アプリでネイティブOS(ノードなど)の機能を使用できるようにしたいのですが、悪用されたくないのです。

コメントで@raddevusによって提起されたnodeIntegration:trueオンにするだけで大​​丈夫です。 ただし、アプリを使用する偶発的/悪意のあるユーザーに対する保護手段として機能し、マシンにインストールされる可能性のあるマルウェアが電子アプリと相互作用して使用するのを防ぐために、 nodeIntegration:falseを維持することを選択します。 nodeIntegration:true攻撃ベクトル(非常にまれですが、発生する可能性があります)!

簡単な方法

BrowserWindowでnodeIntegration: trueを設定すると、レンダラープロセスがノードモジュールにアクセスできるようになります。 _this_を実行すると、脆弱になります。 require("fs")require("electron")にアクセスできますが、これは、誰かがXSSの脆弱性を見つけた場合、レンダラープロセスで公開した任意のコマンド

コンピュータ上のすべてのファイル、または本当に悪い何かを削除することを考えてください。

(代替の)簡単な方法

nodeIntegrationをtrueに設定することに加えて、アプリがwebpackを使用してアプリケーションファイルをバンドルしている可能性があります。 Webpackは特定の記号を台無しにするため、 target: 'electron-renderer'やwebpackの外部設定などの設定でipcRenderer )をアプリに渡すことができます。

それでも、これはアプリの設定方法以外は何も変わりません。

(他の代替)簡単な方法

ipcRendererへのアクセスを提供するリモートモジュールを使用できます。 それは基本的に別の形の「簡単な方法」です。 だお勧めしません、プロトタイプの汚染ベクトルからの攻撃を被るのこのタイプのため、これを行うには、電子のセキュリティ勧告で。

つまり。 リモートを使用すると、誰かがjsオブジェクトのプロトタイプを変更して、マシン/アプリに大混乱をもたらす可能性があります。

_ほぼ_正しい方法

@marksyzmには、完全ではありませんが、IPCを使用してipcRendererをレンダラープロセスに送信する、より優れたソリューションがあります。 このタイプのセットアップは、プロトタイプの汚染攻撃に対しても脆弱です。 アプリを80%使用したい場合は、この方法を使用します。おそらく、多くのリファクタリングを行う必要がないためです。

正しい方法

fs / ipcRendererをレンダラープロセスにインポートする正しい方法は、IPC(プロセス間通信)を使用することです。 これは、メインプロセスとレンダラープロセスの間で会話できるようにするElectronの方法です。 内訳は、次のようにアプリを表示する必要があります。

  1. BrowserWindowにはpreloadプロパティがあります。 このプロパティは、 requireアクセスしてロードするjsファイルです(つまり、ipcRendererが必要になる可能性があります)
  2. BrowserWindowには、プロトタイプの汚染攻撃を防ぐためのcontextIsolation: trueもありますが、これは、 contextBridgeを使用して
  3. プリロードスクリプトとcontextBridgeを使用して、レンダラープロセスがipcRendererにアクセスできるようにします。
  4. メインスクリプトで、( ipcMainモジュール内の)ipcRendererのリスナーを作成します。 これらのリスナー内で、 fsモジュールを使用できます

_大まかに_これは、これらすべての手順がどのように見えるかです。

main.js

const {
  app,
  BrowserWindow,
  ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;

async function createWindow() {

  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false, // is default value after Electron v5
      contextIsolation: true, // protect against prototype pollution
      enableRemoteModule: false, // turn off remote
      preload: path.join(__dirname, "preload.js") // use a preload script
    }
  });

  // Load app
  win.loadFile(path.join(__dirname, "dist/index.html"));

  // rest of code..
}

app.on("ready", createWindow);

ipcMain.on("toMain", (event, args) => {
  fs.readFile("path/to/file", (error, data) => {
    // Do something with file contents

    // Send result back to renderer process
    win.webContents.send("fromMain", responseObj);
  });
});

preload.js

const {
    contextBridge,
    ipcRenderer
} = require("electron");

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
    "api", {
        send: (channel, data) => {
            // whitelist channels
            let validChannels = ["toMain"];
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, data);
            }
        },
        receive: (channel, func) => {
            let validChannels = ["fromMain"];
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender` 
                ipcRenderer.on(channel, (event, ...args) => func(...args));
            }
        }
    }
);

index.html

<!doctype html>
<html lang="en-US">
<head>
    <meta charset="utf-8"/>
    <title>Title</title>
</head>
<body>
    <script>
        window.api.receive("fromMain", (data) => {
            console.log(`Received ${data} from main process`);
        });
        window.api.send("toMain", "some data");
    </script>
</body>
</html>

少なくとも、これらの機能にはエレクトロンv7が必要だと私は信じています。

どうすればこれを知ることができますか?

私は安全な電子アプリに関心があり、セキュリティを後付けとして考えるのではなく、セキュリティを焼き付けるための電子アプリケーションテンプレートを作成するためにsecure-electron-templateを作成しました。

上記の@reZachのコメントにpreload.jsにあり、私のAPIは

main.js

let newWindow = null;
function createWindow() {
    newWindow = new BrowserWindow({
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            enableRemoteModule: false,
            preload: path.join(__dirname, "preload.js")
        }
    });

    newWindow.webContents.on('did-finish-load', () => {
        newWindow.webContents.send('APP_MY_INIT', { data: 'hi' });
    });
}

ipcMain.on('APP_SOMETHING', (event, ...args) => {
    // ...
});

ipcMain.handle('APP_SOMETHING_ELSE', (event, ...args) => {
    // ...
    return myVar;
});

preload.js

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

function callIpcRenderer(method, channel, ...args) {
    if (typeof channel !== 'string' || !channel.startsWith('APP_')) {
        throw 'Error: IPC channel name not allowed';
    }
    if (['invoke', 'send'].includes(method)) {
        return ipcRenderer[method](channel, ...args);
    }
    if ('on' === method) {
        const listener = args[0];
        if (!listener) throw 'Listener must be provided';

        // Wrap the given listener in a new function to avoid exposing
        // the `event` arg to our renderer.
        const wrappedListener = (_event, ...a) => listener(...a);
        ipcRenderer.on(channel, wrappedListener);

        // The returned function must not return anything (and NOT
        // return the value from `removeListener()`) to avoid exposing ipcRenderer.
        return () => { ipcRenderer.removeListener(channel, wrappedListener); };
    }
}

contextBridge.exposeInMainWorld(
    'myIpcRenderer', {
        invoke: (...args) => callIpcRenderer('invoke', ...args),
        send: (...args) => callIpcRenderer('send', ...args),
        on: (...args) => callIpcRenderer('on', ...args),
    },
);

client.js

const { myIpcRenderer } = window;

const removeMyListener = myIpcRenderer.on('APP_MY_INIT', data => {
    console.log(data);
    myIpcRenderer.send('APP_SOMETHING', 'foo');
})

async function test() {
    const result = await myIpcRenderer.invoke('APP_SOMETHING_ELSE', 'foo', 'bar');
    console.log(result);
}
test();

if (/* should remove listener === true */) {
    removeMyListener();
}

TypeScriptを使用している場合は、 types.d.ts

declare global {
    interface Window {
        myIpcRenderer: MyIpcRenderer,
    }
}

export interface MyIpcRenderer {
    invoke(channel: string, ...args: any[]): Promise<any>;
    send(channel: string, ...args: any[]): void;

    /** <strong i="22">@return</strong> A function that removes this listener. */
    on(channel: string, listener: (...args: any[]) => void): () => void;
}

これをpreload.jsに入れようとすると、モジュールが見つからないというエラーが発生する理由を誰かが知っていますか?

const errorLogging = require('../renderer/utils/errorLogging');

ありがとう

@silentlightこれは電子とは関係ありませんが、会話を続けることができる独自のgithubリポジトリがありますか? ( require()パスが正しくないようです。そのため、コードが表示されずにエラーがスローされます)。

すでにwindow.requireソリューションがありますが、楽しみのために、私は私のものを共有します。

function magic(module){
    require(module)
}

const { ipcRenderer } = magic('electron')

ESモジュールまたはCommonJS構文を使用していないため、バンドラーはモジュールをインポートしていることを識別しません。そのため、バンドルしようとしないため、エラーはスローされません。

なぜまだ誰もこれを試したことがないのだろうか😆

@ marc2332 trueですが、この魔法のラッパーによる潜在的な攻撃に直接さらされます。 それはあなたのシナリオには当てはまらないかもしれませんが、間違いなくあなたが考慮すべき懸念事項です。

@reZach正直に言うとwindow.requireがより安全である理由はわかりません。 ところで、それを行うにはもっと汚い方法があります。

const { ipcRenderer } = eval("require('electron')")

@ marc2332どちらも安全ではありません。 リモートアセットを使用している場合は、この方法でインジェクション攻撃にさらされていることに注意してください。 😄

reZachに感謝します! 人々はあなたのアプローチをより早く理解するようになると思います

以上

マーク・エルフィンストーン
www.oxfordsourceltd.com

こんにちはザック、 contextBridgeソリューションはプロトタイプをサポートしていますか?

contextIsolation: false使用した元のコードは、 window関数を付加しただけです。 この関数は、返すPromise<MediaStream>のドキュメントがcontextBridgeプロトタイプがドロップされることを言うと、私は使用したときにcontextBridge私は空のオブジェクトを受け取ります。

プロトタイプをサポートするだけでなく、 contextIsolation: true保証する方法はありますか?

こんにちはザック、 contextBridgeソリューションはプロトタイプをサポートしていますか?

contextIsolation: false使用した元のコードは、 window関数を付加しただけです。 この関数は、返すPromise<MediaStream>のドキュメントがcontextBridgeプロトタイプがドロップされることを言うと、私は使用したときにcontextBridge私は空のオブジェクトを受け取ります。

プロトタイプをサポートするだけでなく、 contextIsolation: true保証する方法はありますか?

いいえ、そうではありません。 チームメンバーの1人が覚えている、これは意図された動作であるというコメントを見つけようとしていましたが、見つかりませんでした。 私が言える最高のことは、Electron v8( pr 20214 )で、IPC内のオブジェクトのシリアル化に変更をもたらし(事実上、コンテキスト分離がオンの場合)、関数またはプロトタイプ。

注:関数、DOMオブジェクト、process.envやWebContentsなどの特別なNode / Electronオブジェクトなど、V8のStructured Cloneアルゴリズムでシリアル化できないオブジェクト、またはそのようなアイテムを含むオブジェクトは、古いbase :: Value-でシリアル化されます。ベースのアルゴリズム。 ただし、この動作は非推奨であり、Electron9以降で例外がスローされます。

これはおそらくあなたが聞きたかったニュースではありませんが、私が助けてくれたことを願っています。

こんにちはザック、 contextBridgeソリューションはプロトタイプをサポートしていますか?
contextIsolation: false使用した元のコードは、 window関数を付加しただけです。 この関数は、返すPromise<MediaStream>のドキュメントがcontextBridgeプロトタイプがドロップされることを言うと、私は使用したときにcontextBridge私は空のオブジェクトを受け取ります。
プロトタイプをサポートするだけでなく、 contextIsolation: true保証する方法はありますか?

いいえ、そうではありません。 チームメンバーの1人が覚えている、これは意図された動作であるというコメントを見つけようとしていましたが、見つかりませんでした。 私が言える最高のことは、Electron v8( pr 20214 )で、IPC内のオブジェクトのシリアル化に変更をもたらし(事実上、コンテキスト分離がオンの場合)、関数またはプロトタイプ。

注:関数、DOMオブジェクト、process.envやWebContentsなどの特別なNode / Electronオブジェクトなど、V8のStructured Cloneアルゴリズムでシリアル化できないオブジェクト、またはそのようなアイテムを含むオブジェクトは、古いbase :: Value-でシリアル化されます。ベースのアルゴリズム。 ただし、この動作は非推奨であり、Electron9以降で例外がスローされます。

これはおそらくあなたが聞きたかったニュースではありませんが、私が助けてくれたことを願っています。

それは残念ですが、迅速な返信に感謝します。

上記の手順( @reZachと@aplumで指定)に従い、 client.jsからpreload.jsmain.js情報を渡します。

すべてをローカルで実行すると通信は機能しますが、 electron-builderを実行すると、通信が切断されます。 たとえば、 setBadge()を使用すると、ローカルで実行するとうまく機能します。 client.jsファイルからカウントを取得し、それがcontextBridgeに渡され、次にmain.jsに渡され、 app.dock.setBadge(count)正常に設定されていることを確認できます。 electron-builder構築された後、Electronの通信に欠けているものはありますか?

"electron": "^8.2.3",
"electron-builder": "^22.4.0",

Main.js

const { ipcMain } = electron;

app.on('ready', () => {
    mainWindow = new BrowserWindow({
        height: height,
        width: width,
        minHeight: 575,
        minWidth: 900,
        center: true,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            enableRemoteModule: false,
            spellcheck: true,
            preload: path.join(__dirname, "preload.js")
        },
    });
}

ipcMain.on('SEND_BADGE_COUNT', (e, count) => {
    const badgeCount = count > 0 ? count : '';
    app.dock.setBadge(`${badgeCount}`)
})

Preload.js

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

contextBridge.exposeInMainWorld(
    'setBadgeCountForElectron', {
        send: (channel, data) => {
            console.log(`Preload ${channel}, ${data}`)
            ipcRenderer.send(channel, data)
        }
    }
)

Client.js

const { setBadgeCountForElectron } = window;

function sendBadgeCount(count) {
  !!setBadgeCountForElectron && setBadgeCountForElectron.send('SEND_BADGE_COUNT', count)
}

sendBadgeCount(count)

package.json

  "name": "desktop_app",
  "version": "0.1.8-beta",
  "private": true,
  "description": "",
  "homepage": "./",
  "main": "public/electron.js",
  "build": {
    "copyright": "Copyright © 2020 My Company",
    "appId": "com.my-app.app",
    "productName": "My Company",
    "buildVersion": "0.0.1-beta",
    "mac": {
      "category": "public.app-category.utilities",
      "icon": "./public/images/mac-icon.png"
    },
    "win": {
      "icon": "./public/images/windows-icon.png"
    },
    "files": [
      "build/**/*",
      "node_modules/**/*"
    ],
    "directories": {
      "buildResources": "assets"
    }
  },

@SterlingChin 、私は電子チームのメンテナーではありませんが、これは電子ビルダーリポジトリに適したより良い質問かもしれません。

少し考えてみると、エレクトロンビルダーではなく、コードの問題だと思う傾向があります。

少し考えてみると、エレクトロンビルダーではなく、コードの問題だと思う傾向があります。

これをすべて期待どおりに機能させるための重要な要素が欠けていると確信しています。 ご返信ありがとうございます。 electron-builderリポジトリで問題を開きましたが、何の牽引力も受けていません。

少し考えてみると、エレクトロンビルダーではなく、コードの問題だと思う傾向があります。

これをすべて期待どおりに機能させるための重要な要素が欠けていると確信しています。 ご返信ありがとうございます。 electron-builderリポジトリで問題を開きましたが、何の牽引力も受けていません。

問題のあるMVPリポジトリを作成しましたか? それは時々助けになり、その過程であなたは何が起こっているのかを理解します。

@Amthieu@CiriousJoker私はあなたを

  1. ヤーン追加-Dcustomize-crareact-app-rewired
  2. package.jsonを変更してreact-app-rewiredstart appを使用します: "start": "BROWSER = none react-app-rewired start"、
  3. 反応アプリのルートディレクトリにファイル「config-overrides」を作成します。
    `const {override} = require( 'customize-cra');

関数addRendererTarget(config){
config.target = 'electron-renderer';

構成を返す;
}

module.exports = override(addRendererTarget); `

  1. 今すぐ 'electron'から{ipcRenderer}をインポートできます:)

vuejsを使用していて、vue.config.jsにコードを追加するだけです

module.exports = {
"transpileDependencies":[
「vuetify」
]、
pluginOptions:{
electronicBuilder:{
nodeIntegration:true
}
}
}

@genilsonmmうまくいった聖なるがらくた! 私は過去3時間夢中になっています。 ありがとう!!
私のために働いたその特定の部分は
`` `javascript
pluginOptions:{
electronicBuilder:{
nodeIntegration:true
}
}、

"transpileDependencies":[
「vuetify」
]、

それは私には機能していません...しかしwindow.require( 'electron')はうまく機能しています

「window.requireは関数ではない」という問題を抱えているすべての人にとって

あなたはtuにelectronのpreoloadスクリプトを作成させました。

  1. de electronicメインスクリプトがあるディレクトリにpreload.jsという名前のファイルを作成し、次のコードをその上に置きます。

    window.require = require;

  2. 電子メインスクリプトに移動し、ウィンドウを作成するコードに次のように入力します。

    win = new BrowserWindow({
    幅:1280、
    高さ:720、
    webPreferences:{
    nodeIntegration:false、
    プリロード:__ dirname + '/ preload.js'
    }、

    })
    これにより、すべての前にスクリプトをプリロードします。これにより、問題が修正されました。 私もあなたのために願っています:)

@reZachあなたの解決策は私のために働きました、しかし私は他の人々がつまずくかもしれないという間違いに気づきました(私がしたので、うわー!):

        receive: (channel, func) => {
            let validChannels = ["fromMain"];
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender` 
                ipcRenderer.on(channel, (event, ...args) => fn(...args));
            }
        }

コールバック関数を「func」として定義しますが、次に「fn」を呼び出します。これを変更すると、記述したとおりに正確に機能します。
ビッグ投稿ありがとうございます:+1:

@genilsonmm vue.config.jsを入れたら:

pluginOptions:{
electronicBuilder:{
nodeIntegration:true、

「requireが定義されていません」というエラーが表示されます:

image

「nodeIntegration:true」という行にコメントすると、エラーメッセージが消え、アプリが動作します。

どういう意味ですか?

@marcoippolitoこれは、webpackにバンドルされているコードがノードjsのモジュール解決方法であるrequireを使用しようとしていることを意味していると思います。 ノード統合を無効にするとこれは利用できないため、コードを実行できません。 あなたがする必要があるのは、ターゲットブラウザにウェブパック設定を変更し(私が正しく覚えていればvarがターゲットです)、どのコードもノードAPIを使用しておらず、エラーがなくなることを確認することです。

TypeScriptを使用している人のために、公式のNext.jsの例に良い例があります。
https://github.com/vercel/next.js/search?q=ipcRenderer&unscoped_q=ipcRenderer

preload.ts

/* eslint-disable @typescript-eslint/no-namespace */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { ipcRenderer, IpcRenderer } from 'electron'

declare global {
  namespace NodeJS {
    interface Global {
      ipcRenderer: IpcRenderer
    }
  }
}

// Since we disabled nodeIntegration we can reintroduce
// needed node functionality here
process.once('loaded', () => {
  global.ipcRenderer = ipcRenderer
})

index.tsx

import { useState, useEffect } from 'react'

const Home = () => {
  const [input, setInput] = useState('')
  const [message, setMessage] = useState(null)

  useEffect(() => {
    const handleMessage = (event, message) => setMessage(message)
    global.ipcRenderer.on('message', handleMessage)

    return () => {
      global.ipcRenderer.removeListener('message', handleMessage)
    }
  }, [])

  const handleSubmit = (event) => {
    event.preventDefault()
    global.ipcRenderer.send('message', input)
    setMessage(null)
  }

  return (
    <div>
      <h1>Hello Electron!</h1>
    </div>
  )
}

export default Home

@genilsonmmうまくいった聖なるがらくた! 私は過去3時間夢中になっています。 ありがとう!!
私のために働いたその特定の部分は

   pluginOptions: {
        electronBuilder: {
            nodeIntegration: true
        }
    },

正解、¸记

NodeIntegrationを有効にすると、この問題も発生します。 window.requireとrequireの両方が機能しません。

+これは反応でのみ発生し、単純な電子では発生しません

このページは役に立ちましたか?
0 / 5 - 0 評価