经历过前两篇的洗礼,相信大家已经掌握了 Electron 基本的用法,那么还在等什么,快上手项目试试吧!

查看原文,获得更好的体验哦~

实践篇将以项目主导,我打算由浅入深从零到一去完成该项目,我们来做一个图片文字识别工具 Electron-OCR,目标如下:

  • 图片上传:拖拽或点击上传
  • 图片预览:上传完成,直接进入预览页,同时执行文字识别
  • 菜单页:简单的导航列表,持续扩充
  • 在线演示功能:提供了更多的图片,便于演示效果
  • 繁体字识别:繁体字需要调用付费接口,所以需要单独处理,增加了繁体校准功能
  • 大图裁切:为了精准识别,需要将图片化繁为简
  • 体验优化:图片识别成功后返回结果,并拷贝入粘贴板,支持语音播报

涉及到的技术如下:

electron, electron-compile, electron-reload, react, react-router@4, react-motion, ES6/ES7, Promise, Surperagent, Less, CSS-Modules, eslint, babelrc, cropper, Material-UI…

一、先睹为快

本文的示例代码已经放在了 Github 上,效果图如下:

你可以直接 clone 项目 npm i & npm run start 运行,或者按照本文的思路一步步实现。

二、创建项目

首先,我们本地创建项目 Electron-OCR-demo,如下:

1
2
3
# 找到合适的目录,创建项目
cd demos
mkdir Electron-OCR-demo

三、初始化项目

1.创建 app 文件夹,用于存放前端项目主体文件;

1
mkdir app

2.创建 service 文件夹,存放请求服务文件以及后端文件;
3.创建 .gitignore 文件:

1
vi .gitignore

并写入规则:

1
2
3
.vscode
node_modules
.log

5.增加 README.md 文件;

1
touch README.md

6.初始化 package.json 文件:

1
npm init

ok,大功告成,我们来同步一下此时的项目结构:

1
2
3
4
5
6
.
├── README.md
├── app
├── .gitignore
├── package.json
└── service

四、快速开始

上面我们做了一些前期的准备工作,既然是用 ELectron 来做,那么当然需要安装依赖了:

1
npm install electron --save-dev

安装比较慢,建议使用淘宝镜像 cnpm install electron --save-dev 来安装。

我们先来运行一个简单示例,进入 app 目录,添加三个文件,分别是:
1.main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const { app, BrowserWindow } = require('electron')
const path = require('path')
const url = require('url')
let mainWindow
function createWindow () {
mainWindow = new BrowserWindow({width: 800, height: 600})
// 启动文件入口,如 index.html
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
// 开启 Chromium DevTools
mainWindow.webContents.openDevTools()
// 监听窗口关闭事件
mainWindow.on('closed', function () {
mainWindow = null
})
}
// 加载就绪
app.on('ready', createWindow)
// 监听所有窗口关闭的事件
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit()
}
})
// 激活窗口
app.on('activate', function () {
if (mainWindow === null) {
createWindow()
}
})

2.index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<script>
// 当然,我们也可以引入其他 js 文件
require('./renderer.js')
</script>
</body>
</html>

3.render.js

1
2
3
4
5
6
let myNotification = new Notification('Jartto', {
body: 'Hello Everybody!'
})
myNotification.onclick = () => {
console.log('Click!')
}

如果你不懂这是在干什么,建议先阅读 初探 Electron - 理论篇

最后一步,设置启动项,打开 package.json
"main": "index.js" 修改为:

1
"main": "app/main.js",

同时增加 "start": "electron ." 配置项,指定使用 Electron 启动:

1
2
3
4
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},

接下来,我们打开命令行,执行:

1
npm run start

如果你看到了窗口中的 Hello World!,那么恭喜你,示例已经正确运行了。

五、继续升级

我们通过手动创建完成了和官网起手项目类似的功能,但路还有些远,我们来做一些升级工作,使用 react 来开发项目。

react 需要额外的一些解析,所以我们借助 electron-compile 来动态编译。

先来安装 react, react-dom, electron-compile,如果太慢请考虑使用 cnpm :

1
2
npm install electron-compilers --save-dev
npm install react react-dom electron-compile --save

因为要预编译文件,所以我们需要为 electron-compile 指定入口文件,在项目根目录下新建 index.js 文件,写入:

注意,记得将 package.json 中,做同步修改 "main": "index.js"


1
2
3
4
const path = require('path');
let appRoot = path.join(__dirname, '');
require('electron-compile').init(appRoot, require.resolve('./app/main'));

这里先指定在 app 目录下的启动文件 main.js,其实也就是该目录下的主进程文件。

接下来,我们用 react 改写一下 render.js,修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React from 'react';
import ReactDOM from 'react-dom';
class MainWindow extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div>
Good, React Ready!
</div>
);
}
}
const mainWndComponent = ReactDOM.render(
<MainWindow/>, document.getElementById('content'));

最后一步,去 index.html 注册 react 组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> Electron-OCR </title>
</head>
<body>
<div id="content"></div>
<script>
require('./render.js');
</script>
</body>
</html>

基本工作完成,我们试着启动一下:

1
npm run start

什么,没启动起来?

Uncaught SyntaxError: Unexpected token import

不要紧张,我们还需要增加个编译规则文件,这很重要!

六、配置编译规则

大家可能都配置过或者间接使用过 babelrc 做转换编译,electron-compile 中的 .compilerc 如出一辙,我们先创建文件:

1
touch .compilerc

然后写入我们的规则,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"env": {
"development": {
"application/javascript": {
"presets": ["env", "react"],
"sourceMaps": "inline",
},
"text/less": {
"dumpLineNumbers": "comments"
}
},
"production": {
"application/javascript": {
"presets": ["env", "react"],
"sourceMaps": "none",
}
}
}
}

这里记得安装依赖包文件 babel-preset-envbabel-preset-react

1
npm install babel-preset-env babel-preset-react --save-dev

OK,搞定,来看看此时我们的 package.json 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"name": "electron-ocr-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"electron",
"demo"
],
"author": "jartto",
"license": "ISC",
"devDependencies": {
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"electron": "^1.7.10",
"electron-compilers": "^5.9.0"
},
"dependencies": {
"electron-compile": "^6.4.2",
"react": "^16.2.0",
"react-dom": "^16.2.0"
}
}

此时的项目结构应该如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── app
│   ├── index.html
│   ├── main.js
│   └── render.js
├── node_modules
│   ├── ...
├── service
├── .compilerc
├── .gitignore
├── index.js
├── package.json
└── README.md

一切就绪,启动 npm run start,如果你看到:Good, React Ready! ,那么恭喜你,reactcompile 文件已经可以正常工作了。

六、热启动

太棒了,美中不足的就是 react 不能热加载,没关系,我们还有 electron-reload,先安装依赖包:

1
npm install electron-reload --save-dev

同时,需要在主进程文件 main.js 中增加如下代码:

1
2
3
4
5
6
7
8
const isDevelopment = true;
if (isDevelopment) {
/* eslint-disable */
require('electron-reload')(__dirname, {
electron: require('${__dirname}/../../node_modules/electron'),
ignored: /node_modules|[\/\\]\./
});
}

重新启动,快更新文件试试吧,热更新也已经就绪了!

七、回顾小结

实践篇,我们从零到一搭建了一个用 react 来开发 electron 的简单框架,完成了支持 es6 的编译配置,同时也添加了热加载。到这里,项目已经初具规模,你可以去做任何想做的事情了~

下一节,我们将继续深入,对框架做一些易用性的优化以及补充,逐步完善项目。传送门在此:初探 Electron - 实践篇2