1, an overview of the

Recently, I need to make a software for PC in my work. This software is basically a courseware making software similar to PPT. Due to my focus on mobile App development in recent years, my understanding of PC development has lagged behind. So I first needed to see what framework would work for me on a PC.

My goal is to be able to learn some of the more popular technologies while completing the software. After preliminary technical research, I made clear the technical conditions needed to realize this software:

  • Don’t use C++ libraries, such as MFC, Qt, DuiLib, etc.
  • I originally wanted to try C# for development, but C# is for me to learn from scratch. If I learn C# only for the development of this software, I will not be able to use it any more.
  • I learned about the mobile development libraryReact NativeAnd so onReactI liked the componentized development, so I decided to try React development.

2. Technical route

Based on the above considerations, I learned about the Electron framework through searching and resolutely adopted the following technical route:

Technical use The document’s official website
Electron Wrap HTML pages to provide a local runtime environment for web pages electron.atom.io/docs/
React Use the React component to write pages facebook.github.io/react/
Node.js Provides an operating environment for Electron nodejs.org/en/docs/
ES6 withJavascriptThe latest ES6 standard to complete the code es6-features.org/#Constants

Electron is a Node.js based superframework that provides a Native shell for HTML pages, And provide localized functions — such as creating Native Windows, file selection dialog, MessageBox, Window menu, Context menu, system clipboard access, and so on. Electron supports Windows/Linux/Mac, so all you need to do is write a piece of JavaScript code and an HTML page and pack it up to run on a different system.

React is mainly used to write pages in a component-based manner, and there are many, many open source components available for React. We just need to import them through NPM.

Since Electron runs in a Node.js environment, our App already has access to all node.js modules – such as the file system, file access, etc. – making it easy for Javascript to manipulate local files. Installing other NPM packages is also a breeze.

3. Environment configuration

Combining the above technologies requires the following environment configuration:

Library & Technical use
electron-prebuilt Basis of Electron library
electron-reload Automatic detectionModify the local file and reload the page
electron-packager Package the final code and present it to the user
react The React based library
react-dom Render the React component into an HTML page (ReactDOM.render)
react-tap-event-plugin makematerial-uiThe library supports button click events (www.material-ui.com/#/get-start…)
babel + babelify Convert ES6 code to a lower version of Javascript code
babel-preset-es2015 Transform ES6 code
babel-preset-react conversionReact JSXSyntactic code
babel-plugin-transform-es2015-spread babelPlug-in to convert ES6spreadgrammar
babel-plugin-transform-object-rest-spread babelPlug-in to convert ES6Object spreadgrammar
browserify + watchify Automatically detect local file modifications and re-convert ES6 code with Babel
Material-UI Google Material-DesignReact UI component style

4. Interactive process of each library

5. Start development

5.1 New project

First we need to install Node.js. Then create a new project with the following command:

npm init

5.2. Add a dependency

This creates a new package.json file in our project directory, and we install the other NPM dependencies. Use the following command:

NPM install – save – dev module_name

NPM install – save module_name

The difference between the –save-dev and –save arguments is: The –save-dev argument adds the added NPM package to devDependencies, which are only used in development environments, while –save adds to the dependencies dependency.

Dependencies like Babel, Watchify, etc., need to be installed under devDependencies, and dependencies like React, etc., need to be installed under Dependencies so that they can be used after being packaged.

We successively installed all the dependencies described in section 3 above via NPM, where the electron related component is very slow to install and has a high probability of failure – if the installation fails, try several times or climb over the wall.

NPM install — save-dev electron-prebuilt electron-reload electron-packager

NPM install — save-dev Babel babelify babel-preset- ES2015 Babel -preset-react babel-plugin-transform-es2015-spread

NPM install — save-dev Browserify watchify

NPM install — save react react-dom react-tap-event-plugin

NPM install – save material – the UI

5.3,babelconfiguration

Once you have Babel installed, you need to configure it. We learned from the Babel website that we need to place a.babelrc file in the project directory to let Babel know which code to convert. Our.babelrc file reads as follows:

{
    "presets": [
        "es2015",
        "react"
    ],

    "plugins": [
        "transform-object-rest-spread"
    ]
}
Copy the code

With presets and plugins, Babel is told to convert ES6 and React JSX style code, as well as the spread syntax in ES6.

5.4,watchify & electron-packager & electronconfiguration

In addition, we need to configure Watchify in the package.json file to automatically detect native code changes and automatically convert code. Package. Json as follows:

/ / package. Json {" name ":" demoapps ", "version" : "1.0.0", "description" : ""," author ":" arnozhang ", "main" : "index.js", "scripts": { "start": "electron .", "watch": "watchify app/appEntry.js -t babelify -o public/js/bundle.js --debug --verbose", "package": "Electron packager./ DemoApps --overwrite --app-version=1.0.0 --platform=win32 --arch=all --out=.. /DemoApps --version=1.2.1 --icon=./public/img/app-icon.icns"}, "devDependencies": {" Babel ": "^ tactical fix packs for 6.5.2", "Babel - plugin - transform - es2015 - spread" : "^ 6.8.0", "Babel - plugin - transform - object - the rest - spread" : "^ 6.8.0", "Babel - preset - es2015" : "^ 6.9.0", "Babel - preset - react" : "^ 6.5.0", "babelify" : "^ 7.3.0", "browserify" : "^ 13.0.1," "electron - packager" : "^ 7.0.3", "electron - prebuilt" : "^ 1.2.1", "electron - reload" : "^ 1.0.0", "watchify" : "^ 3.7.0"}, "dependencies" : {" material - UI ":" ^ 0.15.0 ", "react" : "^ 15.1.0", "react - color" : "2.1.0", "the react - dom" : "^15.1.0", "react-tap-event-plugin": "^1.0.0"}Copy the code

Through package.json file, we configure three commands under scripts: start, watch and package to start App, detect and transform code and package App respectively.

Start: electron. Watch: watchify app/ appentry. js -t babelify -o public/js/bundle.js — debug — verbose package: Electron -packager./ DemoApps – overwrite – app-version=1.0.0 – platform=win32 – arch=all – out=.. / DemoApps – version = 1.2.1 – icon. = / public/img/app – icon. Icns

We can then run the above defined commands from the command line via NPM run XXX. As you can see, babelify outputs the converted code to the public/js/bundle.js directory, so we only need to publish this converted JS file when we publish it.

5.5 Overview of directory structure

Before we start development, let’s take a look at the directory structure of the entire project:

6. Official development

6.1. Electron development mode

Here we have to mention the development mode of Electron. Electron only provides a Native shell for HTML pages, and the business logic needs to be realized by HTML + JS code. Electron provides two processes to complete this task: A main process, responsible for creating Native Windows, Native interaction with the operating system; A rendering process that renders HTML pages and executes JS code. The interaction between the two processes is done via the IPC API provided by Electron.

Since we specified main as index.js in the package.json file, Electron will first load and execute the JS file in the main process — we need to create Windows in the process and call methods to load the page (index.html).

6.2,index.jsThe development of

The index.js file is as follows:

/*
 * Copyright (C) 2016. All Rights Reserved.
 *
 * @author  Arno Zhang
 * @email   [email protected]
 * @date    2016/06/22
 */

'use strict';

const electron = require('electron');
const {app, BrowserWindow, Menu, ipcMain, ipcRenderer} = electron;


let isDevelopment = true;

if (isDevelopment) {
    require('electron-reload')(__dirname, {
        ignored: /node_modules|[\/\\]\./
    });
}


var mainWnd = null;

function createMainWnd() {
    mainWnd = new BrowserWindow({
        width: 800,
        height: 600,
        icon: 'public/img/app-icon.png'
    });

    if (isDevelopment) {
        mainWnd.webContents.openDevTools();
    }

    mainWnd.loadURL(`file://${__dirname}/index.html`);

    mainWnd.on('closed', () => {
       mainWnd = null;
    });
}


app.on('ready', createMainWnd);

app.on('window-all-closed', () => {
    app.quit();
});
Copy the code

This code is very simple. In the App Ready event, the main window is created and the index.html page in the local directory is loaded using the loadURL method of BrowserWindow. In the window-all-closed event of the app, call the app.quit method to exit the entire app.

In addition, we can see that the auto-reload page is automatically reloaded after the local file is updated by introducing the auto-reload module:

require('electron-reload')(__dirname, {ignored: /node_modules|[\/\\]\./});Copy the code

6.3,index.htmlThe development of

The next step is to develop the index.html page, which is also relatively simple:




    
        
        Electron Demo Apps

        
    

    
        
     
Copy the code

As you can see, we define a div with the id content. This div is our container and the React component will render to this div. We then introduce the Javascript file public/js/bundle.js — which, as mentioned earlier, is generated by the Babelify transformation.

6.4,app/appEntry.jsThe development of

As we know, public/js/bundle.js is generated via app/ appentry. js, so the appentry. js file is responsible for HTML page rendering — we implement it via React.

/*
 * Copyright (C) 2016. All Rights Reserved.
 *
 * @author  Arno Zhang
 * @email   [email protected]
 * @date    2016/06/22
 */

'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';

const events = window.require('events');
const path = window.require('path');
const fs = window.require('fs');

const electron = window.require('electron');
const {ipcRenderer, shell} = electron;
const {dialog} = electron.remote;

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';


let muiTheme = getMuiTheme({
    fontFamily: 'Microsoft YaHei'
});


class MainWindow extends React.Component {

    constructor(props) {
        super(props);
        injectTapEventPlugin();

        this.state = {
            userName: null,
            password: null
        };
    }

    render() {
        return (
            
                
     
{this.setState({userName: event.target.value})}}/> {this.setState({password: event.target.value})}}/>
); } _handleLogin() {let options = {type: 'info', buttons: [' confirm '], title: 'login ', message: this.state.userName, defaultId: 0, cancelId: 0 }; dialog.showMessageBox(options, (response) => { if (response == 0) { console.log('OK pressed! '); }}); } _handleRegistry() { } } const styles = { root: { position: 'absolute', left: 0, top: 0, right: 0, bottom: 0, display: 'flex', flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }, icon: { width: 100, height: 100, marginBottom: 40 }, buttons_container: { paddingTop: 30, width: '100%', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' } }; let mainWndComponent = ReactDOM.render( , document.getElementById('content'));Copy the code

Now that we are in the render process, electron must be introduced using window.require, otherwise it will fail. Here, excluding the material- UI part, the main code is:

let mainWndComponent = ReactDOM.render(, document.getElementById('content'));Copy the code

We render a React component onto a div using the reactdom. render method.

7. Up and running

Now that we’re ready to run the program, we’ll start Watchify to monitor local file changes and convert to public/js/bundle.js in real time:

npm run watch

To start the App, call the start command:

npm run start

After running, we immediately see our window:

8, packaging,

The packaging command is simple, but time-consuming:

npm run package

After executing, you can see the packaged folder in the corresponding directory. Compress the folder and provide it to the user to run. To prevent code leaks, you can also package your code as asAR files through the NPM module ASAR.

9, subsequent

Here is just an introduction, you can develop the corresponding App according to your own situation. I found some useful libraries in the process of development, which I note here:

library use
font-detective Check the list of fonts installed on the system
extend Copy an object
draft-js Facebook’s React rich text editor is highly customizable
draft-js-export-html The draft-JS data is converted into HTML code, which is not highly customized. If high customization is required, the code needs to be changed
material-design-icons A series of Material style ICONS can be combined with the Material – UIFontIconuse
md5-file Computes MD5 files in both synchronous and asynchronous modes
node-native-zip File compression and compression, very easy to use
xmlbuilder XML generator, easy to use!Highly recommended
react-color React componentized color picker supports a variety of options!Highly recommended
react-resizeable-and-movable React componentized drag & resize modules
qrcode.react React componentized QR code generator,Highly recommended
request For downloading & uploading