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 library
React Native
And so onReact
I 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 | withJavascript The 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 detection Modify 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-ui The 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 JSX Syntactic code |
babel-plugin-transform-es2015-spread | babel Plug-in to convert ES6spread grammar |
babel-plugin-transform-object-rest-spread | babel Plug-in to convert ES6Object spread grammar |
browserify + watchify | Automatically detect local file modifications and re-convert ES6 code with Babel |
Material-UI | Google Material-Design React 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,babel
configuration
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
& electron
configuration
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.js
The 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.html
The 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.js
The 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 – UIFontIcon use |
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 |