如果Web运用程序员想开拓桌面运用怎么办? 主流的桌面运用开拓技能的学习曲线不低, 上手比较困难. 而Electron的涌现给Web运用程序员带来了福音.
Electron简介:
Electron 是 Github 发布跨平台桌面运用开拓工具,支持 Web 技能开拓桌面运用开拓,其本身是基于 C++ 开拓的,GUI 核心来自于 Chrome,而 JavaScript 引擎利用 v8...

大略的说, Electron平台便是用Javascript把UI和后台逻辑打通, 后台主进程利用NodeJs丰富的API完成繁芜耗时的逻辑, 而UI进程则借助Chrome渲染html完成交互.
我之前利用SpringBoot开拓了一套市长信箱抓取Web运用. 由于没做事器支配, 以是我现在想把同样的功能移植到桌面端, 作成一个桌面运用. 对付开拓平台我有以下需求:
能利用我现有的技能栈: Web前端JavaScript, 做事真个Java或者NodeJs.能跨平台, 既能编译成Mac下的DMG安装程序,又能编译成windows平台下的exe文件, 知足不敷场景的利用.而Electron作为开拓平台恰好能知足我的这些需求, 通过一天的摸索, 我完成了这个桌面运用, 并终极打包出Mac平台下的DMG安装文件. 工程代码: https://github.com/ybak/watcher
下面将先容我是如何利用Electron平台开拓这个桌面运用.
回顾: 市长信箱邮件抓取Web运用
动手之前, 我先剖析一下之前所做的抓取Web运用. 它的架构如下:
运用分可为四部分:
抓取程序:利用Java的OkHttp作为Http要求类库获取网页内容,并交给Jsoup进行解析, 得到邮件内容.数据库:用Mysql实现, 用来保存抓取后的网页内容, 并供应检索查询做事.静态交互页面:一个大略的HTML页面, 利用jQuery发起ajax与后端交互, 并利用handlebar作为展示模板.通信: 利用SpringBoot供应了交互所需的API(搜索做事,全量抓取和更新邮件).设计: 利用Electron构建抓取桌面运用
将要实现的桌面运用, 同样也须要须要完成这四部分的事情. 我做了以下设计:
Electron主进程借助NodeJs丰富的生态系统完成网页抓取与数据存储与搜索的功能, UI进程则完成页面的渲染事情.
抓取程序: 利用NodeJs的Request, cheerio, async完成.数据库: 利用NodeJs下的nedb存储, 作为运用内嵌数据库可以方便的集成进桌面运用.UI: 利用HTML与前端JavaScript类库完成, 重用之前Web运用中的静态页面.通信: 利用Electron供应的IPC,完成主进程与UI进程的通信.实现: 利用Electron构建抓取桌面运用
1. 抓取程序的实现:
市长信箱邮件多达上万封, JavaScript异步的特点, 会让人欠妥心就写出上千并发要求的程序, 短韶光内大量试图和抓取目标做事器建立连接的行为会被做事器谢绝做事, 从而造成抓取流程失落败. 以是抓取程序要做到:
tcp连接复用并发频率可控我利用以下三个NodeJs组件:
Request http客户端, 利用了底层NodeJs的Http KeepAlive特性实现了tcp连接的复用.async 掌握要求的并发以及异步编程的顺序性.cheerio html的解析器.代码: crawlService.js
//利用request获取页面内容request('http://12345.chengdu.gov.cn/moreMail', (err, response, body) => { if (err) throw err; //利用cheerio解析html var $ = cheerio.load(body), totalSize = $('div.pages script').html().match(/iRecCount = \d+/g)[0].match(/\d+/g)[0]; ...... //利用async掌握要求并发, 顺序的抓取邮件分页内容 async.eachSeries(pagesCollection, function (page, crawlNextPage) { pageCrawl(page, totalPageSize, updater, crawlNextPage); })});
2. 数据库的实现:
抓取后的内容存储办法有较多选择:
文本文件搜索引擎数据库文本文件虽然保存大略, 但不利于查询和搜索, 顾不采取.
搜索引擎一样平常须要独立支配, 不利于桌面运用的安装, 这里暂不采取.
独立支配的数据库有和搜索引擎同样的问题, 以是像连接外部Mysql的办法这里也不采取.
综合考虑, 我须要一种内嵌数据库. 幸好NodeJs的组件非常丰富, nedb是一个不错的方案, 它可以将数据同时保存在内存和磁盘中, 同时是文档型内嵌数据库, 利用mongodb的语法进行数据操作.
代码: dbService.js
//建立数据库连接const db = new Datastore({filename: getUserHome()+'/.electronapp/watcher/12345mails.db', autoload: true});......//利用nedb插入数据db.update({_id: mail._id}, mail, {upsert: true}, function (err, newDoc) {});......//利用nedb进行邮件查询let match = {$regex: eval('/' + keyword + '/')}; //关键字匹配var query = keyword ? {$or: [{title: match}, {content: match}]} : {};db.find(query).sort({publishDate: -1}).limit(100).exec(function (err, mails) { event.sender.send('search-reply', {mails: mails});//处理查询结果});
3. UI的实现:
桌面运用的工程目录如图:
我将UI页面放到static文件夹下. 在Electron的进行前端UI开拓和普通的Web开拓办法一样, 由于Electron的UI进程便是一个Chrome进程. Electron启动时, 主进程会实行index.js文件, index.js将初始化运用的窗口, 设置大小, 并在窗口加载UI入口页面index.html.
代码:index.js
function createMainWindow() { const win = new electron.BrowserWindow({ width: 1200, height: 800 });//初始运用窗口大小 win.loadURL(`file://${__dirname}/static/index.html`);//在窗口中加载页面 win.openDevTools();//打开chrome的devTools win.on('closed', onClosed); return win;}
在UI页面开拓的过程中, 有一点须要把稳的是: 默认情形下页面会涌现jQuery, require等组件加载失落败的情形, 这是由于浏览器window加载了NodeJs的一些方法, 和jQuery类库的方法冲突. 以是我们须要做些特殊的处理, 在浏览器window中把这些NodeJs的方法删掉:
代码:preload.js
// 办理require冲突导致jQuery等组件不可用的问题window.nodeRequire = require;delete window.require;delete window.exports;delete window.module;// 办理chrome调试工具devtron不可用的问题window.__devtron = {require: nodeRequire, process: process}
4. 通信的实现:
在Web运用中, 页面和做事的通信都是通过ajax进行, 那我们的桌面运用不是也可以采取ajax的办法通信? 这样理论虽然上可行, 但有一个很大弊端: 我们的运用须要打开一个http的监听端口, 常日个人操作系统都禁止软件打开http80端口, 而打开其他端口也随意马虎和别的程序造成端口冲突, 以是我们须要一种更优雅的办法进行通信.
Electron供应了UI进程和主进程通信的IPC API, 通过利用IPC通信, 我们就能实现UI页面向NodeJs做事逻辑发起查询和抓取要求,也能实现NodeJs做事主动向UI页面关照抓取进度的更新.
利用Electron的IPC非常大略.
首先, 我们须要在UI中利用ipcRenderer, 向自定义的channel发出.
代码: app.js
const ipcRenderer = nodeRequire('electron').ipcRenderer;//提交查询表单$('form.searchForm').submit(function (event) { $('#waitModal').modal('show'); event.preventDefault(); ipcRenderer.send('search-keyword', $('input.keyword').val());//发起查询要求});ipcRenderer.on('search-reply', function(event, data) {//监听查询结果 $('#waitModal').modal('hide'); if (data.mails) { var template = Handlebars.compile($('#template').html()); $('div.list-group').html(template(data)); }});
然后, 须要在主进程实行的NodeJs代码中利用ipcMain, 监听之前自定义的渠道, 就能接管UI发出的要求了.
代码: crawlService.js
const ipcMain = require('electron').ipcMain;ipcMain.on('search-keyword', (event, arg) => { ....//处理查询逻辑});ipcMain.on('start-crawl', (event, arg) => { ....//处理抓取逻辑});
桌面运用打包
办理完以上四个方面的问题后, 剩下的程序写起来就大略了. 程序调试完后, 利用electron-builder, 就可以编译打包出针对不同平台的可实行文件了.