इलेक्ट्रॉन की आवश्यकता () परिभाषित नहीं है


108

मैं अपने उद्देश्य के लिए एक इलेक्ट्रॉन ऐप बना रहा हूं। मेरी समस्या यह है कि जब मैं अपने HTML पृष्ठ के अंदर नोड फ़ंक्शंस का उपयोग कर रहा हूं, तो इसमें त्रुटि होती है:

'आवश्यकता ()' परिभाषित नहीं है।

क्या मेरे सभी HTML पृष्ठों में नोड फ़ंक्शंस का उपयोग करने का कोई तरीका है? यदि यह संभव है तो कृपया मुझे एक उदाहरण दें कि यह कैसे करें या एक लिंक प्रदान करें। यहां वे चर हैं जो मैं अपने HTML पृष्ठ में उपयोग करने का प्रयास कर रहा हूं:

  var app = require('electron').remote; 
  var dialog = app.dialog;
  var fs = require('fs');

और ये वे मान हैं जो मैं अपने सभी HTML विंडो में इलेक्ट्रॉन के भीतर उपयोग कर रहा हूं।


जवाबों:


287

संस्करण 5 के अनुसार, nodeIntegrationसही से गलत में परिवर्तित होने के लिए डिफ़ॉल्ट । ब्राउज़र विंडो बनाते समय आप इसे सक्षम कर सकते हैं:

app.on('ready', () => {
    mainWindow = new BrowserWindow({
        webPreferences: {
            nodeIntegration: true
        }
    });
});

चूंकि इलेक्ट्रॉन के हालिया संस्करण में सुरक्षा कारणों से झूठे डिफ़ॉल्ट डिफ़ॉल्ट है, जो नोड मॉड्यूल तक पहुंचने का अनुशंसित तरीका है? क्या नोडइंटरग्रेशन के बिना मुख्य प्रक्रिया के साथ संवाद करने का एक तरीका है?
पाउलो हेनरिक

28
@PauloHenrique nodeIntegration: trueकेवल एक सुरक्षा जोखिम है जब आप अपने आवेदन पर कुछ अविश्वासित रिमोट कोड निष्पादित कर रहे हैं। उदाहरण के लिए, मान लीजिए कि आपका आवेदन तृतीय पक्ष का वेबपेज खोलता है। यह एक सुरक्षा जोखिम होगा क्योंकि तीसरे पक्ष के वेबपेज में नोड रनटाइम तक पहुंच होगी और आपके उपयोगकर्ता के फाइल सिस्टम पर कुछ दुर्भावनापूर्ण कोड चला सकते हैं। उस मामले में यह सेट करने के लिए समझ में आता है nodeIntegration: false। यदि आपका ऐप कोई दूरस्थ सामग्री प्रदर्शित नहीं कर रहा है, या केवल विश्वसनीय सामग्री प्रदर्शित कर रहा है, तो सेटिंग nodeIntegration: trueठीक है।
xyres

1
यह मुझे पागल कर रहा था। मेरा ऐप बस कोई त्रुटि नहीं दिखाएगा और मेरे कोड को नहीं चलाएगा। यह तब था जब मैंने उस त्रुटि को रोकने के लिए एक कोशिश पकड़ने वाला ब्लॉक का उपयोग किया था जो आखिरकार मुझे यहां लाया।
हेरिबेटो जुआरेज़

2
@PauloHenrique - यदि आप एक सुरक्षित एप्लिकेशन का पालन करना और बनाना चाहते हैं (सुरक्षा सर्वोत्तम प्रथाओं का पालन करना), तो कृपया मेरे सेटअप का पालन करें जैसा कि मैंने इस टिप्पणी में वर्णन किया है: github.com/electron/electron/issues-9920#issuecomment-575839738
Zac

33

सुरक्षा कारणों से, आपको nodeIntegration: falseविंडो वेरिएबल के माध्यम से रेंडर प्रक्रिया (दृश्य) को नोड / इलेक्ट्रॉन एपीआई से जो कुछ भी चाहिए, उसे उजागर करने के लिए एक प्रीलोड स्क्रिप्ट का उपयोग करना चाहिए और उसका उपयोग करना चाहिए । से इलेक्ट्रॉन डॉक्स :

प्रीलोड स्क्रिप्ट में requireअन्य Node.js सुविधाओं तक पहुंच होती है


उदाहरण

main.js

const mainWindow = new BrowserWindow({
  webPreferences: {
    preload: path.join(app.getAppPath(), 'preload.js')
  }
})

preload.js

const { remote } = require('electron');

let currWindow = remote.BrowserWindow.getFocusedWindow();

window.closeCurrentWindow = function(){
  currWindow.close();
}

renderer.js

let closebtn = document.getElementById('closebtn');

closebtn.addEventListener('click', (e) => {
  e.preventDefault();
  window.closeCurrentWindow();
});

1
यदि आप मेरे रूप में एक इलेक्ट्रॉन नौसिखिया हैं: रेंडरर फ़ाइल को आमतौर पर html में क्लासिक तरीके से शामिल किया जाता है:<script src="./renderer.js"></script>
MrAn3

22

मुझे उम्मीद है कि इस उत्तर पर कुछ ध्यान दिया जाएगा, क्योंकि यहां के अधिकांश उत्तर आपके इलेक्ट्रॉन ऐप में बड़े सुरक्षा छेद छोड़ते हैं । वास्तव में यह उत्तर अनिवार्य रूप से है जो आपको require()अपने इलेक्ट्रॉन एप्लिकेशन में उपयोग करने के लिए होना चाहिए । (बस एक नया इलेक्ट्रॉन एपीआई है जो इसे v7 में थोड़ा क्लीनर बनाता है)।

मैंने गथूब में एक विस्तृत विवरण / समाधान लिखा है कि आप require()कुछ कैसे कर सकते हैं, के सबसे वर्तमान इलेक्ट्रॉन एप का उपयोग करते हुए , लेकिन मैं यहां संक्षेप में बताऊंगा कि आपको प्रीलोड लिपि, संदर्भब्रीज और आईपीसी का उपयोग करके दृष्टिकोण का पालन क्यों करना चाहिए।

समस्या

इलेक्ट्रॉन ऐप्स बहुत अच्छे हैं क्योंकि हमें नोड का उपयोग करने के लिए मिलता है, लेकिन यह शक्ति एक दोधारी तलवार है। यदि हम सावधान नहीं हैं, तो हम अपने ऐप के माध्यम से किसी को नोड तक पहुंच प्रदान करते हैं, और नोड के साथ एक बुरा अभिनेता आपकी मशीन को भ्रष्ट कर सकता है या आपकी ऑपरेटिंग सिस्टम फ़ाइलों को हटा सकता है (अन्य बातों के अलावा, मैं कल्पना करता हूं)।

जैसा कि @raddevus द्वारा एक टिप्पणी में लाया गया है, दूरस्थ सामग्री लोड करते समय यह आवश्यक है। यदि आपका इलेक्ट्रॉन ऐप पूरी तरह से ऑफ़लाइन / स्थानीय है , तो आप शायद ठीक हैं बस चालू करें । हालांकि, मैं अभी भी आपके ऐप का उपयोग करने वाले आकस्मिक / दुर्भावनापूर्ण उपयोगकर्ताओं के लिए एक सुरक्षा के रूप में कार्य करने का विकल्प चुनूंगा, और किसी भी संभावित मैलवेयर को रोक सकता हूं जो आपके इलेक्ट्रॉन ऐप के साथ बातचीत करने और हमला वेक्टर (अविश्वसनीय रूप से दुर्लभ) का उपयोग करके कभी भी आपकी मशीन पर स्थापित हो सकता है। , लेकिन हो सकता है)!nodeIntegration:truenodeIntegration:falsenodeIntegration:true

समस्या क्या दिखती है

यह समस्या तब प्रकट होती है जब आप (नीचे का कोई भी):

  1. है nodeIntegration:trueसक्षम
  2. remoteमॉड्यूल का उपयोग करें

ये सभी समस्याएं आपके रेंडरर प्रक्रिया से नोड तक निर्बाध पहुंच प्रदान करती हैं। यदि आपकी रेंडरर प्रक्रिया कभी भी अपहृत है, तो आप विचार कर सकते हैं कि सभी खो गया है।

हमारा समाधान क्या है

समाधान रेंडरर को नोड (यानी। ) तक सीधी पहुंच नहीं देना है require(), लेकिन हमारे इलेक्ट्रॉन को मुख्य प्रक्रिया तक पहुंच प्रदान करना है require, और कभी भी हमारी रेंडरर प्रक्रिया का उपयोग करने की आवश्यकता है require, मुख्य प्रक्रिया के लिए एक अनुरोध को मार्शल करें।

जिस तरह से यह इलेक्ट्रॉन के नवीनतम संस्करणों (7+) में काम करता है वह रेंडरर पक्ष पर है जिसे हमने ipcRenderer बाइंडिंग सेट किया है , और मुख्य तरफ हम ipcMain बाइंडिंग सेट करते हैं। IpcMain बाइंडिंग में हम श्रोता विधियों को सेट करते हैं जो हम मॉड्यूल का उपयोग करते हैं require()। यह ठीक और ठीक है क्योंकि हमारी मुख्य प्रक्रिया यह requireसब चाहती है।

हम का उपयोग contextBridge हमारे एप्लिकेशन कोड (उपयोग करने के लिए) के लिए ipcRenderer बाइंडिंग पारित करने के लिए, और इसलिए हमारे एप्लिकेशन की जरूरत का उपयोग करने के लिए जब requireमुख्य में घ मॉड्यूल, यह भारतीय दंड संहिता (अंतर-प्रक्रिया-संचार) और मुख्य प्रक्रिया रन के माध्यम से एक संदेश भेजता है कुछ कोड, और हम फिर अपने परिणाम के साथ एक संदेश वापस भेजते हैं।

मोटे तौर पर , यहाँ आप क्या करना चाहते हैं।

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>

अस्वीकरण

मैं secure-electron-templateइलेक्ट्रॉन एप्लिकेशन बनाने के लिए एक सुरक्षित टेम्पलेट का लेखक हूं । मैं इस विषय की परवाह करता हूं, और कुछ हफ्तों से (इस समय इस बिंदु पर) काम कर रहा हूं।


मैं नया इलेक्ट्रॉनजेस डेवलपर हूं और एक प्लुरसाइट ट्यूटोरियल के माध्यम से काम कर रहा था जो अब एनएएसई नोड एकीकरण सेटिंग्स को नहीं चलाता है। आपकी पोस्ट बहुत अच्छी है और मैं आपके संबंधित Github पोस्ट और संबंधित आधिकारिक इलेक्ट्रॉन सुरक्षा डॉक्स को भी पढ़ रहा हूं। नोड एकीकरण को ठीक से सेट करना (ताकि एप्लिकेशन ठीक से काम करें और सुरक्षित रहें) में बहुत सारे चलती हिस्से हैं (विशेषकर नौसिखिया के लिए)। इलेक्ट्रॉन डॉक्स से वाक्य के बाद "यह सर्वोपरि है कि आप किसी भी रेंडरर (BrowserWindow, BrowserView, या <webview>) में Node.js एकीकरण को सक्षम नहीं करते हैं जो दूरस्थ सामग्री लोड करता है। " (मेरा जोर)
raddev

मैं मान रहा हूं कि उलटा सच है ... "अगर BrowserWindow दूरस्थ सामग्री लोड नहीं करता है, तो यह नोड एकीकरण को शामिल करना सुरक्षित है"। यदि वह वाक्य सही है, तो आप इस बिंदु पर जोर देने के लिए अपनी पोस्टों में थोड़ा बदलाव करना चाह सकते हैं क्योंकि मेरे मामले में मेरे पास दो ऐप्स हैं जो उस श्रेणी में आते हैं और नोड एकीकरण को हटाने की आवश्यकता नहीं है। आपकी सहायता के लिए धन्यवाद।
राडदेवस

1
@raddevus धन्यवाद, मुझे आशा है कि टेम्पलेट आपको सुरक्षित इलेक्ट्रॉन एप्लिकेशन बनाने में मदद करता है (यदि आप इसका उपयोग करना चुनते हैं)! हां, आप अपने जोर पर सही हैं। हालाँकि, मैं कहूंगा कि nodeIntegrationउपयोगकर्ता को एप्लिकेशन का उपयोग करते समय गलती से या जानबूझकर खुद को नुकसान पहुंचाने से रोकता है, और एक अतिरिक्त सुरक्षा के मामले में कुछ मैलवेयर आपकी इलेक्ट्रॉन प्रक्रिया से जुड़ा हुआ था और XSS प्रदर्शन करने में सक्षम था यह जानते हुए कि यह वेक्टर खुला था (अविश्वसनीय रूप से) दुर्लभ है, लेकिन यह वह जगह है जहां मेरा दिमाग चला गया)!
ज़ैक

1
@raddevus धन्यवाद, मैं आपकी टिप्पणी को प्रतिबिंबित करने के लिए अपनी पोस्ट अपडेट कर रहा हूं।
Zac

9

क्या आप nodeIntegration: falseBrowserWindow इनिशियलाइज़ेशन के दौरान उपयोग कर रहे हैं ? यदि ऐसा है, तो इसे निर्धारित करें true(डिफ़ॉल्ट मान है true)।

और अपनी बाहरी लिपियों को HTML में इस तरह शामिल करें (जैसे नहीं <script> src="./index.js" </script>):

<script>
   require('./index.js')
</script>

मैं इस के साथ ऑफ़लाइन js ऑफ़लाइन का उपयोग कर रहा हूं। जब मैं नोडइन्ग्रेशन का उपयोग कर रहा हूं : तो सच है PDFJS.getDocument एक फ़ंक्शन त्रुटि नहीं आएगीनोड सेट करने के लिए कैसे करें । मेरे HTML पृष्ठ में PDFs पूरी तरह से लोड होने पर सच: एचटीएमएल पेज सेट करें ।
मारी सेलवन

क्या आपने इस उदाहरण को देखा है ? आप पैकेज को केवल var pdfjsLib = require('pdfjs-dist')इस तरह आयात कर सकते हैं और उसका उपयोग कर सकते हैं।
रॉयलबिंगबोंग

आप requireइसके बजाय उपयोग करने की सलाह क्यों देते हैं <script src="..."></script>? यह भी यहाँ एक अनुत्तरित प्रश्न है
bluenote10

@ bluenote10 वेबपैक इस सवाल का जवाब देता है : यह बताना मुश्किल है कि एक स्क्रिप्ट क्या निर्भर करती है, निर्भरता क्रम को प्रबंधित किया जाना चाहिए, और अनावश्यक कोड अभी भी डाउनलोड और निष्पादित किया जाएगा।
हाईकम

7

सबसे पहले, @Sathiraumesh सॉल्यूशन आपके इलेक्ट्रॉन एप्लिकेशन को भारी सुरक्षा समस्या के साथ छोड़ देता है। कल्पना करें कि आपके ऐप में कुछ अतिरिक्त सुविधाएँ जोड़ी जा रही हैं messenger.com, उदाहरण के लिए टूलबार का आइकन बदल जाएगा या पलक झपकते ही आपके पास कोई अपठित संदेश आ जाएगा। तो अपनी main.jsफ़ाइल में, आप नए BrowserWindow बनाते हैं जैसे (ध्यान दें कि मैंने जानबूझकर messenger.com को गलत किया है):

app.on('ready', () => {
    const mainWindow = new BrowserWindow({
        webPreferences: {
            nodeIntegration: true
        }
    });
    mainWindow.loadURL(`https://messengre.com`);
});

अगर messengre.comकोई दुर्भावनापूर्ण वेबसाइट है, जो आपके कंप्यूटर को नुकसान पहुंचाना चाहती है। यदि आप सेट करते हैं तो nodeIntegration: trueइस साइट की आपके स्थानीय फ़ाइल प्रणाली तक पहुँच है और इसे निष्पादित कर सकते हैं:

require('child_process').exec('rm -r ~/');

और आपकी होम डाइरेक्टरी चली गई है।

समाधान
केवल वही करें जो आपको चाहिए, बजाय सब कुछ के। यह requireकथनों के साथ जावास्क्रिप्ट कोड को प्रीलोड करने से प्राप्त होता है।

// main.js
app.on('ready', () => {
    const mainWindow = new BrowserWindow({
        webPreferences: {
            preload: `${__dirname}/preload.js`
        }
    });
    mainWindow.loadURL(`https://messengre.com`);
});
// preload.js
window.ipcRenderer = require('electron').ipcRenderer;
// index.html
<script>
    window.ipcRenderer.send('channel', data);
</script>

अब भयानक messengre.comआपके पूरे फाइल सिस्टम को नहीं हटा सकता है।


-1

अंत में, मैंने इसे काम कर दिया। इस कोड को अपने HTML दस्तावेज़ स्क्रिप्ट एलिमेंट में शामिल करें।

उत्तर के लिए क्षमा करें। मैं इस काम को करने के लिए नीचे दिए गए कोड का उपयोग करता हूं।

window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;

और उपयोग nodeRequireकरने के बजाय उपयोग करें require

यह बढ़िया काम करता है।


कृपया अपना HTML पेज कोड साझा करें।
विजय

-1

आपको इसका उपयोग करने के लिए WebPreferences में नोड- इनग्रेडेशन को सक्षम करना होगा। निचे देखो,

const { BrowserWindow } = require('electron')
let win = new BrowserWindow({
  webPreferences: {
    nodeIntegration: true
  }
})
win.show()

इलेक्ट्रान 5.0 ( रिपोजिटरी पर घोषणा ) में ब्रेकिंग एपि परिवर्तन था । हाल के संस्करणों में नोडइंटरग्रेशन डिफ़ॉल्ट रूप से गलत पर सेट है ।

डॉक्स के Node.js एकीकरण के कारण, मॉड्यूल में कुछ अतिरिक्त प्रतीकों को डाला जाता है जैसे मॉड्यूल, निर्यात, आवश्यकता। यह कुछ पुस्तकालयों के लिए समस्या का कारण बनता है क्योंकि वे प्रतीकों को एक ही नाम के साथ सम्मिलित करना चाहते हैं। इसे हल करने के लिए, आप इलेक्ट्रॉन में नोड एकीकरण को बंद कर सकते हैं:

लेकिन अगर आप Node.js और इलेक्ट्रॉन एपीआई का उपयोग करने की क्षमता रखना चाहते हैं, तो आपको अन्य पुस्तकालयों को शामिल करने से पहले पेज में प्रतीकों का नाम बदलना होगा:

<head>
    <script>
        window.nodeRequire = require;
        delete window.require;
        delete window.exports;
        delete window.module;
    </script>
    <script type="text/javascript" src="jquery.js"></script>
</head>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.