Electron: Kesalahan saat mengimpor elektron dalam reaksi | impor { ipcRenderer } dari 'elektron'

Dibuat pada 3 Jul 2017  ·  65Komentar  ·  Sumber: electron/electron

Saya telah membuat aplikasi reaksi sederhana dengan create-react-app dan saya telah berhasil mengintegrasikannya dengan elektron. Semuanya berfungsi dengan baik sampai saya mencoba mengimpor elektron di dalam file pembuat tindakan. Jika saya menghapus baris di bawah ini, aplikasi berfungsi dengan baik. Masalahnya adalah saya tidak dapat menggunakan ipcRenderer untuk berkomunikasi dari sisi reaksi ke proses utama elektron.

Baris ini menyebabkan aplikasi mogok:
import { ipcRenderer } from 'electron';

Saya mendapatkan kesalahan berikut:

TypeError: fs.existsSync bukan fungsi
(fungsi anonim)
node_modules/electron/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')

Saya menemukan di Google bahwa ini adalah masalah umum ketika mencoba mengimpor elektron.

Terima kasih untuk bantuannya

Komentar yang paling membantu

@MarshallOfSound kesalahan saya.

Saya menemukan solusinya dalam masalah #7300 jika itu dapat membantu siapa pun.

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

Harap dicatat bahwa ini akan bekerja ketika Anda menjalankan aplikasi Electron, tetapi jika Anda hanya ingin menguji kode React Anda di dalam browser, itu akan tetap macet (window.require tidak ditentukan di browser seperti di Electron).

Semua 65 komentar

CRA menggunakan webpack yang mengacaukan pemuatan modul standar (termasuk fs).

Saya akan merekomendasikan melihat ke mode Electron untuk webpack dan mengeluarkan dari CRA

Masalah GitHub adalah untuk permintaan fitur dan laporan bug, pertanyaan tentang penggunaan Electron harus diarahkan ke komunitas atau ke Slack Channel .

@MarshallOfSound kesalahan saya.

Saya menemukan solusinya dalam masalah #7300 jika itu dapat membantu siapa pun.

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

Harap dicatat bahwa ini akan bekerja ketika Anda menjalankan aplikasi Electron, tetapi jika Anda hanya ingin menguji kode React Anda di dalam browser, itu akan tetap macet (window.require tidak ditentukan di browser seperti di Electron).

Jika Anda ingin mengakses app.quit(), Anda dapat menggunakan ini:

const { app } = window.require('electron').jarak jauh;

Mungkin itu membantu seseorang ...

@CiriousJoker ini solusinya, terima kasih!

Saya masih mendapatkan window.require is not a function . Saya menggunakan Electron dengan React Starter Kit (https://github.com/kriasoft/react-starter-kit). Semuanya bekerja dengan baik, kecuali ini.

Saya telah mengatur aplikasi Electron saya untuk memuat aplikasi saya dari web, sehingga aplikasi tidak berjalan secara lokal:
https://Gist.github.com/holgersindbaek/68f6db82f507967a51ca75c527faeff6

Apa yang saya coba lakukan, adalah memanggil ipcRenderer di salah satu file React saya. Saya tidak yakin apakah itu mungkin ketika aplikasi saya sedang dimuat dari web. Ada saran?

@holgersindbaek

Di kapal yang sama dengan Anda... Apakah Anda menemukan solusi?

Tidak. Saya cukup yakin tidak mungkin memuat ipcRenderer dari browser.

Jika Anda menjalankan aplikasi React Anda di browser, itu tidak akan berfungsi. Jalankan di dalam Electron dan Anda akan baik-baik saja.

@Amthieu Terima kasih atas sarannya. Saya masih ragu bagaimana saya bisa menjalankan proyek React saya (berdasarkan React Starter Kit) di Electron. Setiap saran akan sangat dihargai:

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

Benar, saya punya solusi.

1) Buat preload.js file dengan kode:

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

2) Pramuat file ini di main.js Anda melalui webPreferences :

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

3) Sekarang, Anda akan memiliki akses dari aplikasi reaksi Anda. Misalnya ini akan berhasil:

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

Catatan - menggunakan ini: https://github.com/cheton/is-electron untuk fungsi isElectron()

@HemalR Langkah 3 harus sebagai berikut (sekarang):

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

Catatan : window.isElectron bukan fungsi.

@nparsons08

Permintaan maaf - seharusnya menambahkan dari mana saya mendapatkan isElectron, telah mengedit contoh kode saya dengan tautan ke: https://github.com/cheton/is-electron

@holgersindbaek
Apakah ada solusi sekarang?

bagi saya hanya berfungsi jika nodeIntegration adalah true ;

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

bekerja dengan baik solusi

sekarang BAGAIMANA mengirim DARI elektron KE Bereaksi?

mencoba dengan
di sisi elektron

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

tetapi tidak ada yang diterima dari pendengar Bereaksi

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

apakah benar menggunakan ipcMain.emit() atau haruskah saya menggunakan yang lain?

ok baru saja ditemukan saya harus menggunakan (pada proses utama elektron)

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

terimakasih untuk semuanya!

Saya mencoba semua hal di atas tetapi tidak berhasil. Apa yang berhasil bagi saya adalah peretasan raksasa. Ubah file ./node_modules/electron/index.js dan hard code path ke electron.exe

misalnya

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

module.exports = getElectronPath();

Wow, saya tidak bisa membuat IPCRenderer bekerja pada Komponen Bereaksi saya. Saya sudah mencoba semua cara di atas. Apakah ada di antara Anda yang kebetulan memiliki petunjuk yang bisa saya gunakan agar bisa berfungsi? Terima kasih

Hmmm ... Aplikasi elektron saya masih berfungsi dengan baik menggunakan solusi saya di atas - tetapi saya belum memperbaruinya dalam beberapa bulan sekarang (belum perlu).

Saya ingin tahu apakah ada perubahan besar yang akan menghentikan ini bekerja? Mungkin kalian dapat memposting versi elektron Anda?

@cyclonstep Apakah ada kesalahan spesifik yang Anda dapatkan? Sulit untuk membantu tanpa potongan kode atau beberapa log ...

Saya menggunakan parsel untuk bundling.
Window.require juga menyelesaikannya untuk saya (juga menunjukkan, apa yang tidak):

impor Vue dari 'vue/dist/vue.min'
impor Aplikasi dari './Aplikasi'

// BURUK? impor { ipcRenderer } dari 'elektron'
// BURUK? const { ipcRenderer } = membutuhkan('elektron')
// BAGUS:
const { ipcRenderer } = window.require('electron')

( lebih jauh di bawah dalam file yang sama adalah elektron "pong-Demo" , yang agak membuktikan, itu berfungsi)

Mungkin perlu diperhatikan: Bahkan ketika melakukannya dengan salah, ukuran bundel tidak bertambah (bandingkan dengan tanpa kebutuhan elektron. Sejauh ini, ini adalah impor elektron pertama&sejauh ini hanya sisi render saya) dengan seluruh ukuran Elektron atau semacamnya, tetapi hanya sekitar 20kb , yang tampaknya merupakan kode shim/wrapper tersendiri, berasal dari 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

Bagaimanapun, semuanya bekerja seperti yang dikatakan di atas.

Node versi 10.2.0
Chrome versi 66.0.3359.181
Elektron versi 3.0.2

window.require tidak berfungsi untuk saya di skrip utama saya dengan kesalahan window is not defined , jadi saya beralih ke const electron = eval('require')("electron") . Semoga ini bisa membantu seseorang. Menggunakan webpack, dan masalahnya adalah webpack mengevaluasi pernyataan kebutuhan saya pada waktu kompilasi.

@MarshallOfSound kesalahan saya.

Saya menemukan solusinya dalam masalah #7300 jika itu dapat membantu siapa pun.

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

Harap dicatat bahwa ini akan bekerja ketika Anda menjalankan aplikasi Electron, tetapi jika Anda hanya ingin menguji kode React Anda di dalam browser, itu akan tetap macet (window.require tidak ditentukan di browser seperti di Electron).

Dan untuk TypeScript:

import {IpcRenderer} from 'electron';

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

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

@moshfeu Solusi Anda bekerja dengan fantastis. Saya tidak perlu Webpack atau Browserfy untuk menggunakan IpcRenderer di proyek React saya. Terima kasih banyak lagi :D

Untuk TypeScript dan menggunakan contoh nodeIntegration: true : https://github.com/electron/electron/issues/9920#issuecomment -336757899:

Benar, saya punya solusi.

  1. Buat preload.js file dengan kode:
window.ipcRenderer = require('electron').ipcRenderer;
  1. Pramuat file ini di main.js Anda melalui webPreferences :
  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      preload: __dirname + '/preload.js'
    }
  });
  1. Sekarang, Anda akan memiliki akses dari aplikasi reaksi Anda. Misalnya ini akan berhasil:
componentDidMount() {
      if (isElectron()) {
          console.log(window.ipcRenderer);
          window.ipcRenderer.on('pong', (event, arg) => {
              this.setState({ipc: true})
          })
          window.ipcRenderer.send('ping')
      }
  }

Catatan - menggunakan ini: https://github.com/cheton/is-electron untuk fungsi isElectron()

dikombinasikan dengan
https://github.com/electron/electron/issues/9920#issuecomment -447157348

Saya menggunakan ini:

import { IpcRenderer } from 'electron';

declare global {
  interface Window {
    ipcRenderer: IpcRenderer
  }
}

export const { ipcRenderer } = window;

Harapan yang membantu seseorang di luar sana! Bekerja dengan stenciljs, dan saya membayangkan reaksi dan sudut

cukup tambahkan target: "electron-renderer" di konfigurasi webpack.
ekspor default {
...
target: "penyaji elektron"
...
}

Hai, saya menggunakan CRA + Elektron. Dan saya membangun proyek saya dengan target 'electron-renderer'. Ini berfungsi dengan baik saat memuat file di folder build, tetapi menimbulkan kesalahan ketika saya mengembangkan dan memuat url localhost:3000 . Saya kira alasannya adalah saya menggunakan api simpul dan api elektron dalam komponen reaksi. Ada yang punya solusinya? Terima kasih.

TypeError: fs.existsSync is not a function

Yah, fs api tidak tersedia di browser. Jika saya memahami situasinya dengan benar, Anda menjalankan aplikasi Anda menggunakan react-scripts start (yang merupakan skrip default npm start di CRA).

Cara yang tepat untuk melakukannya adalah dengan menjalankan electron . . Anda dapat melihatnya di dokumen: https://electronjs.org/docs/tutorial/first-app.

LMK jika berhasil untuk Anda. Anda juga dapat melihat cara kerjanya di aplikasi saya - https://github.com/moshfeu/y2mp3 (Perhatikan bahwa itu tidak dibuat dengan CRA)

Hai, saya menggunakan CRA + Elektron. Dan saya membangun proyek saya dengan target 'electron-renderer'. Ini berfungsi dengan baik saat memuat file di folder build, tetapi menimbulkan kesalahan ketika saya mengembangkan dan memuat url localhost:3000 . Saya kira alasannya adalah saya menggunakan api simpul dan api elektron dalam komponen reaksi. Ada yang punya solusinya? Terima kasih.

TypeError: fs.existsSync is not a function

cukup tambahkan target: "electron-renderer" di konfigurasi webpack.
ekspor default {
...
target: "penyaji elektron"
...
}

Ini bekerja untuk saya juga.

Ini versi alat saya:

  • paket web: "3.8.1"
  • elektron: "4.2.1"

Saya pikir electron-renderer hanya untuk menyelesaikan masalah elektron ini. Saya tidak perlu menggunakan sintaks kabel seperti window.required , dan bahkan kehilangan pengetikan!

Bagi saya berhasil mengatur target: "rendering elektron" untuk webpack dan nodeIntegration: true di opsi BrowserWindow
Saya menggunakan webpack+electron+react dari versi terakhir hari ini

Saya menjalankan create-react-app dengan TypeScript an Electron. Saya mengikuti instruksi yang sangat bagus ini untuk pengaturan. Tapi kemudian saya juga mengalami kesalahan ini. Solusi yang berhasil bagi saya adalah jumlah dari hal-hal yang dikatakan di utas ini:

  1. Buat skrip reaksi gunakan "electron-renderer" sebagai target . Saya menggunakan rescripts dengan rescript-env untuk ini.

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. Tambahkan simpulIntegrasi
new BrowserWindow({
  webPreferences: {
    nodeIntegration: true
  }
});
  1. Tambahkan src/typings.d.ts :
declare var window: Window;
interface Window {
  require: any;
}

Dan akhirnya kamu ada di aplikasimu

App.tsx

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

@LukasBombach
Ini harus bekerja juga:

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

Kemudian Anda akan mengetik pada const yang diperlukan

Terima kasih!

Berikut adalah langkah-langkah yang saya gunakan untuk Vue jika ini berguna untuk orang lain.

Pastikan integrasi node diaktifkan untuk proses perender dengan menambahkannya ke preferensi web saat membuat jendela browser:

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',
    },
}

Impor apa yang Anda butuhkan dalam aplikasi Anda. Saya mengimpor modul Shell ke dalam komponen saya seperti:

import { shell } from 'electron'

Untuk siapa saja yang masih memiliki masalah yang sama. Ini adalah solusi terbaik yang saya temukan sejauh ini

```js
Jendela Browser baru({
webPreferensi: {
simpulIntegrasi: benar
}
});

Saya harap komentar ini diperhatikan, karena banyak orang bertanya tentang mengimpor fs atau ipcRenderer di aplikasi Anda. Ini adalah kebutuhan umum untuk aplikasi elektron tetapi saya menemukan tidak banyak orang yang melakukannya dengan benar, dan menggunakan pola yang sudah ketinggalan zaman. tl;dr - ada kerentanan keamanan jika Anda tidak mengimpor modul node (mis. fs ) atau modul elektron (mis. ipcRenderer ) dengan cara yang benar. Jika Anda menggunakan aplikasi hanya untuk diri sendiri, Anda _mungkin_ aman, tetapi jika Anda ingin membagikan atau menjual aplikasi Anda, Anda harus membaca terlebih dahulu.

Tujuan kita

Sebelum saya membahas solusinya, penting untuk memahami _mengapa_ kita melakukan ini sejak awal. Aplikasi elektron memungkinkan kami untuk memasukkan modul simpul di aplikasi kami, yang memberi mereka kekuatan luar biasa, tetapi masalah keamanan. Kami ingin mengizinkan aplikasi kami menggunakan fitur native-os (mis. node), tetapi kami tidak ingin fitur tersebut disalahgunakan .

Seperti yang dikemukakan oleh nodeIntegration:true . Namun, saya tetap akan memilih untuk menyimpan nodeIntegration:false untuk bertindak sebagai perlindungan bagi pengguna yang tidak sengaja/berbahaya menggunakan aplikasi Anda, dan mencegah kemungkinan malware yang mungkin pernah diinstal pada mesin Anda agar tidak berinteraksi dengan aplikasi elektron Anda dan menggunakan vektor serangan nodeIntegration:true (sangat jarang, tetapi bisa terjadi)!

Cara mudah

Menyetel nodeIntegration: true di BrowserWindow Anda memberikan akses proses perender Anda ke modul node. Melakukan _this_, rentan. Anda memiliki akses ke require("fs") dan require("electron") , tetapi itu berarti jika seseorang menemukan kerentanan XSS, mereka dapat menjalankan perintah apa pun yang telah Anda buka dalam proses perender Anda.

Pikirkan untuk menghapus semua file di komputer Anda, atau hal lain yang sangat buruk.

Cara mudah (alternatif)

Selain menyetel nodeIntegration ke true, kemungkinan aplikasi Anda menggunakan webpack untuk menggabungkan file aplikasi. Webpack mengacaukan simbol tertentu, jadi pengaturan seperti target: 'electron-renderer' atau webpack eksternal memungkinkan Anda untuk melewati variabel-variabel ini ( ipcRenderer ) ke dalam aplikasi Anda.

Namun, ini tidak mengubah apa pun kecuali cara Anda mengatur aplikasi Anda.

Cara mudah (alternatif lainnya)

Anda dapat menggunakan modul jarak jauh yang memberi Anda akses ke ipcRenderer . Ini pada dasarnya 'Cara mudah' dalam bentuk yang berbeda. Tidak disarankan oleh

Yaitu. menggunakan jarak jauh dapat memungkinkan seseorang untuk memodifikasi prototipe objek js dan merusak mesin/aplikasi Anda.

_hampir_ cara yang benar

@marksyzm memiliki solusi yang lebih baik , meskipun tidak sempurna, di mana kami menggunakan IPC untuk mengirim ipcRenderer ke proses renderer. Jenis pengaturan ini juga rentan terhadap serangan polusi prototipe . Jika Anda ingin mendapatkan aplikasi Anda 80% dari perjalanan ke sana, saya akan menggunakan metode ini, karena mungkin Anda tidak perlu melakukan banyak refactoring.

Jalan yang benar

Cara yang benar untuk mengimpor fs / ipcRenderer Anda ke dalam proses renderer Anda adalah dengan IPC (inter-process-communication). Ini adalah cara Electron memungkinkan Anda untuk berbicara antara proses utama dan penyaji. Dipecah, beginilah tampilan aplikasi Anda:

  1. BrowserWindow memiliki properti preload . Properti ini adalah file js yang memuat dengan akses ke require (yang berarti Anda dapat memerlukan ipcRenderer)
  2. BrowserWindow Anda juga akan memiliki contextIsolation: true untuk mencegah serangan polusi prototipe, tetapi ini berarti Anda perlu menggunakan contextBridge untuk meneruskan ipcRenderer ke proses perender Anda
  3. Dengan menggunakan skrip pramuat dan contextBridge, Anda mengizinkan proses perender Anda untuk mengakses ipcRenderer
  4. Dalam skrip utama Anda, Anda membuat pendengar untuk ipcRenderer (dalam modul ipcMain ). Dalam pendengar ini Anda dapat menggunakan modul fs

_Kira-kira_ seperti inilah tampilan semua langkah ini:

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>

Setidaknya, saya _percaya_ Anda membutuhkan elektron v7 untuk fitur ini.

Bagaimana saya tahu ini?

Saya peduli dengan aplikasi elektron yang aman, dan membuat secure-electron-template untuk membuat template aplikasi elektron untuk meningkatkan keamanan alih-alih memikirkan keamanan sebagai renungan.

Membangun komentar @reZach di atas, saya melakukan sesuatu seperti berikut ini. Perbedaan utama adalah di preload.js , di mana API saya lebih dekat dengan ipcRenderer.

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),
    },
);

klien.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();
}

Dan bagi mereka yang menggunakan 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;
}

Adakah yang tahu mengapa saya mendapatkan kesalahan modul tidak ditemukan ketika saya mencoba memasukkan ini ke preload.js?

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

Terima kasih

@silentlight ini tidak terkait dengan elektron, apakah Anda mungkin memiliki repo github sendiri di mana percakapan dapat dilanjutkan? (Sepertinya jalur Anda di require() tidak benar dan itulah sebabnya ini menimbulkan kesalahan, tanpa melihat lebih banyak kode).

Meskipun sudah ada solusi window.require , saya akan membagikan milik saya, hanya untuk bersenang-senang:

function magic(module){
    require(module)
}

const { ipcRenderer } = magic('electron')

Pembundel Anda tidak akan mengidentifikasi saat Anda mengimpor modul karena Anda tidak menggunakan modul ES atau sintaks CommonJS, sehingga tidak akan mencoba untuk memaketkannya sehingga tidak akan menimbulkan kesalahan

Saya bertanya-tanya mengapa belum ada yang mencoba ini

@ marc2332 benar, tetapi kemudian Anda secara langsung mengekspos diri Anda terhadap potensi serangan oleh pembungkus ajaib ini. Ini mungkin tidak berlaku untuk skenario Anda, tetapi jelas merupakan masalah yang harus Anda pertimbangkan.

@reZach Saya tidak melihat alasan mengapa window.require lebih aman untuk jujur. Btw, ada cara yang lebih kotor untuk melakukannya.

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

@ marc2332 tidak ada yang aman. Saya hanya mencatat, jika Anda menggunakan aset jarak jauh, Anda membuka diri terhadap serangan injeksi dengan cara ini. 😄

Terima kasih reZach! Saya pikir orang akan memahami pendekatan Anda lebih cepat

atau nanti

Mark Elphinstone
www.oxfordsourceltd.com

Hai Zach, apakah solusi contextBridge mendukung prototipe?

Kode asli saya dengan contextIsolation: false cukup melampirkan fungsi pada window . Fungsi ini mengembalikan Promise<MediaStream> namun dokumen contextBridge mengatakan bahwa prototipe dijatuhkan dan ketika saya menggunakan contextBridge saya menerima objek kosong.

Apakah ada cara untuk mendukung prototipe tetapi juga memastikan contextIsolation: true ?

Hai Zach, apakah solusi contextBridge mendukung prototipe?

Kode asli saya dengan contextIsolation: false cukup melampirkan fungsi pada window . Fungsi ini mengembalikan Promise<MediaStream> namun dokumen contextBridge mengatakan bahwa prototipe dijatuhkan dan ketika saya menggunakan contextBridge saya menerima objek kosong.

Apakah ada cara untuk mendukung prototipe tetapi juga memastikan contextIsolation: true ?

Tidak. Saya mencoba mencari komentar yang saya ingat dari salah satu anggota tim bahwa ini adalah perilaku yang disengaja tetapi saya tidak bisa. Yang terbaik yang bisa saya katakan adalah di Electron v8, ( pr 20214 ) membawa perubahan pada serialisasi objek dalam IPC (efektif ketika isolasi konteks aktif) yang akan menjatuhkan dukungan (saat ini tidak digunakan lagi, akan dihapus di versi mendatang) untuk fungsi atau prototipe.

CATATAN: Objek yang tidak dapat dibuat serial dengan algoritma Klon Terstruktur V8, seperti fungsi, objek DOM, objek Node/Elektron khusus seperti process.env atau WebContents, atau objek apa pun yang berisi item tersebut akan diserialisasikan dengan basis lama::Nilai- algoritma berbasis. Namun, perilaku ini tidak digunakan lagi dan akan mengeluarkan pengecualian yang dimulai dengan Elektron 9.

Ini mungkin bukan berita yang ingin Anda dengar, tetapi saya harap saya membantu.

Hai Zach, apakah solusi contextBridge mendukung prototipe?
Kode asli saya dengan contextIsolation: false cukup melampirkan fungsi pada window . Fungsi ini mengembalikan Promise<MediaStream> namun dokumen contextBridge mengatakan bahwa prototipe dijatuhkan dan ketika saya menggunakan contextBridge saya menerima objek kosong.
Apakah ada cara untuk mendukung prototipe tetapi juga memastikan contextIsolation: true ?

Tidak. Saya mencoba mencari komentar yang saya ingat dari salah satu anggota tim bahwa ini adalah perilaku yang disengaja tetapi saya tidak bisa. Yang terbaik yang bisa saya katakan adalah di Electron v8, ( pr 20214 ) membawa perubahan pada serialisasi objek dalam IPC (efektif ketika isolasi konteks aktif) yang akan menjatuhkan dukungan (saat ini tidak digunakan lagi, akan dihapus di versi mendatang) untuk fungsi atau prototipe.

CATATAN: Objek yang tidak dapat dibuat serial dengan algoritma Klon Terstruktur V8, seperti fungsi, objek DOM, objek Node/Elektron khusus seperti process.env atau WebContents, atau objek apa pun yang berisi item tersebut akan diserialisasikan dengan basis lama::Nilai- algoritma berbasis. Namun, perilaku ini tidak digunakan lagi dan akan mengeluarkan pengecualian yang dimulai dengan Elektron 9.

Ini mungkin bukan berita yang ingin Anda dengar, tetapi saya harap saya membantu.

Sangat disayangkan, tapi terima kasih atas balasan cepat Anda.

Saya telah mengikuti langkah-langkah yang diuraikan di atas (diberikan oleh @reZach dan @aplum), dan saya meneruskan informasi dari client.js ke preload.js ke main.js .

Saat menjalankan semuanya secara lokal, komunikasi berfungsi, tetapi ketika saya menjalankan electron-builder , komunikasi terputus. Misalnya, menggunakan setBadge() bekerja sangat baik ketika dijalankan secara lokal. Saya dapat menghitung dari file client.js dan melihatnya diteruskan ke contextBridge dan kemudian ke main.js dan berhasil mengatur app.dock.setBadge(count) . Apakah ada sesuatu yang saya lewatkan dengan komunikasi di Electron setelah dibangun dengan electron-builder ?.

"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}`)
})

Pramuat.js

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

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

klien.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 , saya bukan pemelihara dengan tim elektron, tetapi ini mungkin pertanyaan yang lebih cocok untuk repo pembuat elektron.

Saya lebih cenderung berpikir ini adalah masalah dengan kode daripada pembangun elektron ketika saya meluangkan waktu untuk memikirkannya.

Saya lebih cenderung berpikir ini adalah masalah dengan kode daripada pembangun elektron ketika saya meluangkan waktu untuk memikirkannya.

Saya yakin saya kehilangan beberapa bagian penting yang akan membuat ini semua berfungsi seperti yang diharapkan. Terima kasih atas tanggapan Anda. Saya telah membuka masalah di repo electron-builder , tetapi belum menerima daya tarik apa pun.

Saya lebih cenderung berpikir ini adalah masalah dengan kode daripada pembangun elektron ketika saya meluangkan waktu untuk memikirkannya.

Saya yakin saya kehilangan beberapa bagian penting yang akan membuat ini semua berfungsi seperti yang diharapkan. Terima kasih atas tanggapan Anda. Saya telah membuka masalah di repo electron-builder , tetapi belum menerima daya tarik apa pun.

Sudahkah Anda membuat repo MVP dengan masalah Anda? Itu terkadang membantu dan dalam prosesnya Anda menyadari apa yang sedang terjadi.

@Amthieu dan @CiriousJoker aku cinta kalian berdua, terima kasih.

  1. yarn add -D customize-cra react-app-rewired
  2. ubah package.json untuk menggunakan aplikasi awal react-app-rewired: "start": "BROWSER=none react-app-rewired start",
  3. buat file 'config-override' di direktori root aplikasi reaksi:
    `const { override } = membutuhkan('customize-cra');

fungsi addRendererTarget(config) {
config.target = 'penyaji elektron';

kembali konfigurasi;
}

module.exports = override(addRendererTarget);`

  1. anda dapat mengimpor { ipcRenderer} dari 'elektron' sekarang :)

Saya menggunakan vuejs dan cukup tambahkan kode di vue.config.js

modul.ekspor = {
"transpileDependencies": [
"vuetifikasi"
],
opsi plugin: {
elektronPembangun: {
simpulIntegrasi: benar
}
}
}

@genilsonmm Astaga, berhasil! Aku sudah gila selama 3 jam terakhir. Terima kasih!!
Bagian spesifik dari itu yang berhasil untuk saya adalah
```javascript
opsi plugin: {
elektronPembangun: {
simpulIntegrasi: benar
}
},

"transpileDependencies": [
"vuetifikasi"
],

itu tidak bekerja pada saya...tetapi window.require('electron') bekerja dengan baik

Untuk semua orang yang memiliki masalah "window.require bukan fungsi"

Anda harus membuat skrip preoload pada elektron.

  1. Buat file bernama preload.js di direktori tempat Anda memiliki skrip utama de elektron, Letakkan kode ini di atasnya:

    window.require = membutuhkan;

  2. Buka skrip utama elektron Anda dan ketik ini dalam kode tempat Anda membuat jendela:

    menang = jendela Browser baru({
    lebar: 1280,
    tinggi: 720,
    webPreferensi: {
    simpulIntegrasi: salah,
    pramuat: __dirname + '/preload.js'
    },

    })
    Dengan ini Anda akan memuat skrip terlebih dahulu, ini memperbaiki masalah bagi saya. aku juga berharap sama kamu :)

@reZach solusi Anda berhasil untuk saya, tetapi saya melihat kesalahan yang mungkin membuat orang lain tersandung (karena saya melakukannya, woops!):

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

Anda mendefinisikan fungsi panggilan balik Anda sebagai "func" , tetapi kemudian memanggil "fn", jika Anda mengubahnya, ini berfungsi persis seperti yang Anda gambarkan.
Besar Terima kasih atas pos terperincinya :+1:

@genilsonmm Jika saya meletakkan vue.config.js :

opsi plugin: {
elektronPembangun: {
simpulIntegrasi: benar,

Saya mendapatkan kesalahan "persyaratan tidak ditentukan":

image

Jika saya mengomentari baris "nodeIntegration: true" pesan kesalahan menghilang dan aplikasi berfungsi.

Apa artinya?

@marcoippolito Saya percaya itu berarti kode paket webpack mencoba menggunakan require yang merupakan metode resolusi modul node js. Karena ini tidak tersedia jika Anda menonaktifkan integrasi simpul, maka kode tidak dapat dijalankan. Yang perlu Anda lakukan adalah memodifikasi konfigurasi webpack Anda untuk menargetkan browser ( var adalah target jika saya ingat dengan benar) dan memastikan bahwa tidak ada kode Anda yang menggunakan node apis dan kesalahannya akan hilang.

Bagi mereka yang menggunakan TypeScript, ada contoh bagus di contoh Next.js resmi:
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 Astaga, berhasil! Aku sudah gila selama 3 jam terakhir. Terima kasih!!
Bagian spesifik dari itu yang berhasil untuk saya adalah

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

正 解, 标记

Saya memiliki masalah ini juga dengan NodeIntegration diaktifkan. Baik window.require dan require tidak berfungsi.

+Ini hanya terjadi dengan reaksi, bukan elektron biasa

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

ThorstenHans picture ThorstenHans  ·  3Komentar

PhilAndrew picture PhilAndrew  ·  3Komentar

rhnorskov picture rhnorskov  ·  3Komentar

dangan-ronpa picture dangan-ronpa  ·  3Komentar

christiangenco picture christiangenco  ·  3Komentar