We already have a really basic main process set up. It's creating a browser window that loads index.html. In our index.html, we have a button that when pressed will open a new window. Then we're requiring in our renderer.js file.
Let's use Remote to see how we'd wire up that create window button to open a new window when it's clicked. In our renderer.js, let's require Remote from Electron. We're also going to need Path from Node.js core as well.
In our click callback handler on the new window button, let's create our window. We're going to do new remote.BrowserWindow. We'll give it a height of 400 and a width of 400. Then just like in the main process, we're going to load in index.html.
Now, let's try our open new window button. We see that works. It just came in right on top of it. You can see that Remote is a little easier to work with than IPC. It's more direct, and it allows you to interact with main process modules as if they were present in the renderer.
You can see we accessed it using remote.BrowserWindow. All main process modules are available to the renderer process off of the Remote module. Remote may seem like magic, but it's not.
Let's start it again, and let's look at the console. I opened this with command-alt-I on Mac. On Windows, it'll be control-shift-I. Here's the remote. We can see these are all the main process modules, browser window, menu, etc.
The Electron team has made a dev tools extension that you can use in Electron called Devtron. Let's NPM install that, npm install --save-dev devtron. Then at the top of our renderer.js, we'll require Devtron, and then call install.
Let's run our app again. We'll open our dev tools, and we see we have a Devtron tab now. Let's go to the IPC tab, move this over, and we'll call record. Let's open a new window. This is recording all of the IPC that happens.
We can see when we click open new window, quite a bit happens. This is all being called by Electron internally, but you can see that in order for Remote to do its work, it's using synchronous IPC to make it happen.
Remote has some other handy methods on it. For example, if we wanted to get the current browser window instance that we're in, we'll say current window is equal to remote.getCurrentWindow(). Let's say that we wanted to change the style of the page based on whether the window is blurred or focused.
Let's create a function called onblur. Here, we'll set the document's style. Give it opacity 02. On focus, we want to restore that to one. We'll call our get current window, and we'll say on onblur, call onblur. Then on focus, call onfocus. Let's run our start script and see what that looks like.
Let's open a new window. We can see it in action here. When we focus or blur, the opacity here drops to 02. Then when we come back, it's restored to one. Something like would be tedious to implement in IPC, but now it's really easy.
However, there are some caveats to be aware of. For example, let's refresh our page with command-R or F5, and then focus, blur. You can see we're getting errors here from the main process.
I'll expand this. It says, "Attempting to call a function in a renderer window that has been closed or released," and it gives the traceback to our file here in line 24, onfocus.
What's going on here? What do these mean? In a nutshell, this is a memory leak. Whenever we refresh the page, the web content instance is destroyed and then recreated. The event listener that we attached right here, onfocus, onblur, these aren't freed automatically.
We have to free them explicitly. Let's see how we fix that. Let's call window.addEventListener() before onload. Call current window, remove listener. We'll pass onfocus, and we'll do the same for blur. Let's try this out. Open another window, and then we'll refresh this one and switch back between them.
We can see there's no errors being thrown over here, so that worked. Remote can definitely make things easier, but it requires some care when you're registering remove event listeners in particular. There's a lot more that Remote can do, actually.
This covers the main use cases of reaching into the main process from the renderer process and interacting with main process modules. We sure to take a look at the Electron documentation and see everything that you can do with it.