Correctly utilizing preload.js in Electron: A comprehensive guide
P粉197639753
2023-08-27 20:25:30
<p>I tried using a node module (in this case <code>fs</code>) in my <code>renderer</code> process like this: </p>
<pre class="brush:php;toolbar:false;">// main_window.js
const fs = require('fs')
function action() {
console.log(fs)
}</pre>
<p><sup>Note: When I press the button in <code>main_window</code>, the <code>action</code> function is called. </sup></p>
<p>But this produces the error: </p>
<pre class="brush:php;toolbar:false;">Uncaught ReferenceError: require is not defined
at main_window.js:1</pre>
<p>I was able to solve this problem, as this accepted answer suggests, by adding these lines to my <code>main.js</code> when initializing <code>main_window</code> Medium: </p>
<pre class="brush:php;toolbar:false;">// main.js
main_window = new BrowserWindow({
width: 650,
height: 550,
webPreferences: {
nodeIntegration: true
}
})</pre>
However, according to the documentation, this is not the best practice, I should create a <code>preload.js</code> file and load these Node modules in it, and then in all my <code>renderer</code> Use it in the process.Like this:<p><br /></p>
<p><code>main.js</code>:</p>
<pre class="brush:php;toolbar:false;">main_window = new BrowserWindow({
width: 650,
height: 550,
webPreferences: {
preload: path.join(app.getAppPath(), 'preload.js')
}
})</pre>
<p><code>preload.js</code>:</p>
<pre class="brush:php;toolbar:false;">const fs = require('fs')
window.test = function() {
console.log(fs)
}</pre>
<p><code>main_window.js</code>:</p>
<pre class="brush:php;toolbar:false;">function action() {
window.test()
}</pre>
<p>And it works! </p>
<hr />
<p>Now my question is, isn't it counterintuitive that I should write most of the code for the <code>renderer</code> process in <code>preload.js</code> (since only I only have access to the Node module in <code>preload.js</code>) and then just call the functions in each <code>renderer.js</code> file (like here, <code>main_window. js</code>)? What don't I understand here? </p>
Consider this example
Not everything in the official documentation can be implemented directly anywhere in the code. You must need to have a concise understanding of the environment and processes.
Context isolation and node integration
contextIsolation
nodeIntegration
Fake
Fake
Fake
true
true
Fake
true
true
How to use preloading correctly?
You must use Electron's inter-process communication (IPC) in order for the main process and the renderer process to communicate.
BrowserWindow.webContents.send() code>
Method to send messages to the rendereripcMain.handle()
Method to receive messages from the rendererImplementation example
main
Preloading
Renderer
How about using Promise?
Keep commitments to the same process/environment whenever possible. Your promises on main should remain on main. Your commitment to the renderer should also remain on the renderer. Don't make a commitment to jump from the main program to the preloader to the renderer.
File system
Most of your business logic should still be on the main or renderer side, but it should never be in preloading. This is because preloading exists almost exclusively as a medium. The preload should be very small.
In OP's case,
fs
should be implemented on the master side.Edited 2022
I've published a larger article about the history of Electron (how security has changed in Electron versions) and other security considerations that Electron developers can take to ensure that new applications Use preload files correctly in the program.
Edit 2020
As another user asked, let me explain my answer below.
The correct way to use
preload.js
in Electron is to expose a whitelist wrapper around any modules that your app mayrequire
.From a security perspective, anything exposed
require
or retrieved via arequire
call inpreload.js
is dangerous (see my comment for more explanation why). This is especially true if your application loads remote content (which many applications do).In order to do this correctly, you need to create a new window in BrowserWindow as I detail below. Setting these options forces your Electron application to communicate via IPC (Inter-Process Communication) and isolates the two environments from each other. Setting up your application like this allows you to validate anything in the backend that might be a
require
module without it being tampered with by the client.Below, you'll find a short example of what I'm talking about and how it might look in your app. If you are new to this, I might recommend using
secure-electron-template
(I am the author of it) to incorporate all these security best practices from the start when building electron applications .This page also has good information on the architecture required when using preload.js to make secure applications.
main.js
preload.js
index.html