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
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.
- Buat
preload.js file
dengan kode:window.ipcRenderer = require('electron').ipcRenderer;
- Pramuat file ini di main.js Anda melalui
webPreferences
:mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: false, preload: __dirname + '/preload.js' } });
- 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:
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:
"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;
};
new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
});
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.
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 menyimpannodeIntegration: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 serangannodeIntegration:true
(sangat jarang, tetapi bisa terjadi)!
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.
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.
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.
@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.
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:
preload
. Properti ini adalah file js yang memuat dengan akses ke require
(yang berarti Anda dapat memerlukan ipcRenderer)contextIsolation: true
untuk mencegah serangan polusi prototipe, tetapi ini berarti Anda perlu menggunakan contextBridge untuk meneruskan ipcRenderer ke proses perender AndaipcRenderer
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.
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
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 padawindow
. Fungsi ini mengembalikanPromise<MediaStream>
namun dokumencontextBridge
mengatakan bahwa prototipe dijatuhkan dan ketika saya menggunakancontextBridge
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 dengancontextIsolation: false
cukup melampirkan fungsi padawindow
. Fungsi ini mengembalikanPromise<MediaStream>
namun dokumencontextBridge
mengatakan bahwa prototipe dijatuhkan dan ketika saya menggunakancontextBridge
saya menerima objek kosong.
Apakah ada cara untuk mendukung prototipe tetapi juga memastikancontextIsolation: 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",
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}`)
})
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld(
'setBadgeCountForElectron', {
send: (channel, data) => {
console.log(`Preload ${channel}, ${data}`)
ipcRenderer.send(channel, data)
}
}
)
const { setBadgeCountForElectron } = window;
function sendBadgeCount(count) {
!!setBadgeCountForElectron && setBadgeCountForElectron.send('SEND_BADGE_COUNT', count)
}
sendBadgeCount(count)
"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.
fungsi addRendererTarget(config) {
config.target = 'penyaji elektron';
kembali konfigurasi;
}
module.exports = override(addRendererTarget);`
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.
Buat file bernama preload.js di direktori tempat Anda memiliki skrip utama de elektron, Letakkan kode ini di atasnya:
window.require = membutuhkan;
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":
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 adalahpluginOptions: { 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
Komentar yang paling membantu
@MarshallOfSound kesalahan saya.
Saya menemukan solusinya dalam masalah #7300 jika itu dapat membantu siapa pun.
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).