📜 ⬆️ ⬇️

We collect Electron.js rake or desktop JS-applications in practice

image

Electron is a system that allows you to create cross-platform applications using only web technologies, such as HTML, CSS, and of course, JS.

It should be noted that the development on Electron is very much different from the usual browser-server application on Node. What this article will be about.

For a detailed introduction to Electron, welcome here and there .
')
About six months ago, I learned about Electron. Then I implemented a simple Phaser based platformer. Js, and felt the complete delight of how quickly and conveniently this platform allows you to create applications. However, this experience was postponed until better times.

Then I had to work only with Canvas, and all the main logic was created by means of Phaser and connecting scripts. No special architecture was required by the application. However, a week ago there was a need for a small desktop utility, and the choice fell on Electron as a development platform. And then wrap ...

Yes, for those who are interested in developing something playable on Electron: WebGL application runs faster than in a regular browser. Oddly enough, Chrome, on which Electron is based, shows itself the worst. However, the difference is not much greater.

Here is the frame-by-frame schedule (the benchmark was this example, with object deletion disabled):

image

Well, go ahead. Let's try to write something sensible.

Initially, I thought about the elementary convenience of development. I needed at least some kind of architecture, and I used to refresh my knowledge of JS frameworks. The choice fell on Backbone.js. It is known for its ease, and, which in this case is a giant plus, it is not tied to the web at all. Backbone, in my opinion, can be an excellent basis for both the server application and the browser and the desktop itself.

As I said, Electron is not the same as Chrome and the locally running Node that responds to it.

If you go a little deeper into the structure of the Electron, then it is rather cut off in terms of the browser features of Chromium and Node.js built into it. (not to be confused with the "bare" V8 in the usual delivery of the browser).

image

Application execution starts with this code:

//main.js //     const electron = require('electron'); const app = electron.app; const BrowserWindow = electron.BrowserWindow; let mainWindow; function createWindow () { // Create the browser window. mainWindow = new BrowserWindow({ width: 800, height: 600, //fullscreen:true, frame:false, resizable:false }); //  mainWindow.loadURL('file://' + __dirname + '/views_html/startscreen/index.html'); // html  mainWindow.on('closed', function() { mainWindow = null; }); } //   app.on('ready', createWindow); //     app.on('window-all-closed', function () { if (process.platform !== 'darwin') { app.quit(); } }); //        OS X app.on('activate', function () { . if (mainWindow === null) { createWindow(); } }); //  

A more detailed analysis of the links at the beginning of the article.

This code is executed in Node, with all the advantages and disadvantages. Based on his work, a window is generated with WebKit and the environment for executing JavaScript. The environment is the same Node that launched the application, but the initialization code and the code of your application cannot interact with each other.

Simply put, main.js creates a window configuration and is responsible for integrating the application into the system. Index.html is the entry point directly into the application you have developed. They cannot interact directly with each other. It is impossible to transfer a variable from main to a script connected to the loaded html, despite the fact that they are executed one after the other on the same virtual machine.

But not directly possible. There are two ways to transfer data from the initialization code to the application itself. The first is pretty obvious registration of a global object. One of these is process, and it contains all the information about the environment in which the application runs:

 !DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Hello World!</title> </head> <body> <h1>Hello World!</h1>   Node <script>document.write(process.versions.node)</script>, Chrome <script>document.write(process.versions.chrome)</script>,  Electron <script>document.write(process.versions.electron)</script>. </body> </html> 

Running this code will display the Node, Cromium, and Electron versions.

Naturally, you can add your object and display it in the same way.

And the second way. Execution of code within your application, a kind of RPC. It will look like this:

  mainWindow.webContents.executeJavaScript( //      `alert("Hello from runtime!");`); //   

Here it is worth considering that:

The code specified in executeJavaScript () will be executed only after the page loads. Therefore, it is impossible in this way to initialize variables that are critical for the start of the application. There is, of course, an option and the application itself in this way to start by wrapping the startup script in the function and:

  mainWindow.webContents.executeJavaScript( //      `alert("Hello from runtime!");`; //   start_up(); // ); 

This is clearly not the best solution.

To be honest, this approach surprised me somewhat. In my opinion, it would be much more convenient for some things, like loading configuration files and other parts that do not change in the course of execution, to load along with the initialization of the window.

However, it is not for nothing that I mentioned that the “browser” part of the application also runs inside the Node, therefore you have the full right to use the modules as installed using npm:

 npm install backbone npm install jquery 

 var Backbone = require('backbone'); var $ = require('jquery'); 

So connect your own parts of the application with:

 require("path_to_file"); 

But here is waiting for a giant underwater rock.

In normal development on Node.js, we can include the file in this way:

 require("./app"); 

This code will tell the application to include the app file located in the same directory as the script that is running. But in the "browser" part of Electron, paths that begin with a slash or "./" do not work .

By default, it looks in the node_modules folder in the application root, and if you specify:

 require("modules/app"); //     modules   node_modules require("/modules/app"); // => Error require("./modules/app"); // => Error,     

In the same time:

 require("modules/../app"); //  app   node_modules 

will work as it should.

Be careful.

Naturally, this situation did not suit me. I definitely didn’t want to spread the application by daddy in the directory for runtime modules. I got out of the situation like this:

 function require_file(file) { require("modules/../../js/app/modules/"+file); // modules       node_modules } 

Crutch Definitely. But now I can include the parts of the application I need by specifying:

 require_file("show"); // show -   

Let's return to our structure. I chose this approach:

 <!-- index.html --> <script type="text/javascript" src="../../js/app/system_init.js"></script> 

The system_init file is the only linkable script in the html file.

It contains:

 var Backbone = require('backbone'); //  var $ = require('jquery'); 

A number of other helper functions like loading configuration files and launching an application:

 var router = new APP.SystemRouter({ menus: new APP.SystemCollection() }); 

Further implementation of the classic backbone application, with the removal of logically separate parts into modules and connecting them with:

 require_file("/path/module"); 

Looking ahead, I’ll say that we managed to realize dynamic loading / unloading of modules, but about this some time next.

Source: https://habr.com/ru/post/278951/


All Articles