Electron入门指北
最近几年最火的桌面化技术,无疑是Qt+和Electron。
两者都有跨平台桌面化技术,并不局限于Windows系统。前者因嵌入式而诞生,在演变过程中,逐步完善了生态以及工具链。后者则是依托于Node.Js和CCM(Chromium Content Module),支持Node.js和Node.js原生以及自主封装的Electron API。
因为项目考虑跨平台的技术选型,研究过长达一年的Electron,并且做了很多尝试,所以想与诸君分享Electron的技术心得。
Electron的特点
Electron依赖于Node.js,只要会用Node.js开发程序的,都可以用Electron开发桌面应用,只需要前端结合Electron API,就可以快速完成桌面应用,一处代码,多处编译。
Electron的优势
可以编译在Windows、Mac、Linux的X64/x86环境,因为是系统独立打包,不依赖运行时。
页面开发依赖于Node.js加前端,可以很便捷的采用前端开发页面,再通过Electron API结合的形式,Electron API可以理解为一套Node原生库,实际上安装也就是一句 npm install electron
Electron内核采用Chromium,可以兼容主流浏览器,并不需要额外适配,而且采用Chromium LST(长期支持版本),并不会过于激进的选择最新版本,减少了前端为了兼容适配带来的风险性。
另一方面,采用前端做UI层,可以减少UI对于系统的适配情况。
Electron的应用场景
由于采用了Node.js和前端的开发模式,本身是一个嵌套了浏览器的本地化前端应用,适合一些没有底层操作的应用场景,甚至前端页面可以是远程地址,这样子完全可以完成桌面应用的无缝热更新
技术的局限性
Electron采用的核心架构是Node.js,所以一旦涉及非页面展示层的功能,比如要与com交互,要操作底层库,比如各种硬件交互的SDK XX.dll,这里就需要参考Node原生来编写原生扩展了。
Node原生编写
参照Node.js官网的原生扩展,编写一个简单的例子
执行npm init
创建一个默认的package.json
以下代码保存为 hello.cc
#include <node.h>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(
isolate, "world"));
}
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
}
以下代码保存为 binding.gyp
{
"targets": [
{
"target_name": "hello",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [ "hello.cc" ],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
}
]
}
执行两个命令 node-gyp configure node-gyp build
如果提示命令不存在,则 npm install node-gyp
命令很简单 前者是生成项目文件,后者则是编译文件,生成 hello.node ,至于为什么叫hello.node,可以参考 binding.gyp/targets/target_name
以下代码保存为 index.js
var addon = require('./build/Release/hello');
console.log(addon.hello()); // 'world'
运行 node . ,显示

遭遇滑铁卢
好像一切都挺顺利的
按照Electon的例子,编写index.js
const { app, BrowserWindow } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
win.loadURL('https://electronjs.org')
var addon = require('./hello');
console.log(addon.hello()); // 'world'
}
console.log(process.versions.node);
app.whenReady().then(createWindow);
代码本身可以运行起来,但是加入了调用Node原生之后就提示

这明显不能用啊,而且很认真的保持了Electron内部Node.js和外部编译插件的Node.js的一致性
柳暗花明
参考了electron官方例子未果后,反复搜索资料,一一验证,最后发现,要在node-gyp编译的时候,标注版本
node-gyp configure --target=版本号 --dist-url=https://atom.io/download/atom-shell
node-gyp build --target=版本
看见了node-gyp,你以为是编译的node对应版本的插件?no,这里编译的是electron对应的版本

程序运行成功的那一刻,我差点口吐芬芳,不带这么坑人的
社会的险恶
程序也跑起来了,是不是 “天晴了雨停了,感觉自己又行了”
这才第一步呢,实际上node.js原生的写法是专属写法,带有大量的侵入式的插件设计,这块不亚于重写学一门C语言的亚种 (比如Object-C和C的差别)
这还只是自己撰写原生扩展,如果是海量API组合的呢?这个扩展要写成什么样?所幸社区开发了一种神器,叫FFI
此时应有掌声
你以为这里是为你鼓掌的?不,这只是开启了探索星辰大海的第一步,告诉你,不要哭,未来哭的日子还长呢。
FFI的编译文章千千万,编译不成功的文章更是数不胜数,没有一篇资料阐述了FFI与Node之间晦涩不明的版本关系 ,也没有一篇文章告诉你,如何成功安装。
成功的都是侥幸,失败,那才是人生。
小伙计,你已经上了黑车,车门焊死了。
Electron常见的雷区
Electron的浏览器内核叫 CCM(Chromium Content Modult),是不是有CEF小伙伴已经嗷嗷叫了?这个自带了mp4支持,不用再编译了,是不是更兴奋了,幸福来的太突然?
先别忙,瞅一眼Electron API,你品,你细品。
是不是没有CEF常见的各种扩展Handler?没错,CEF重度产品,至少在默认的Electron框架上,是很多做不了的,比如截取浏览器区域的webgl renderer/render的产品,比如各种音乐播放器,基于音频的Handler二次混合叠加的产品,在默认实现上,做不了。
对于前端框架的改动
常见的一些前端小组件被移除,常见的比如localstroge、sessionstroge不可用,需要搜索一些三方的组件替代性使用,比如electron-localstroge。
常见的Window.Open被修改,实现指向了Electron.BrowserWindow。
发布
Electron本身的发布其实没有什么问题的,一旦引入了原生扩展,发布的时候,就需要小心的重新编译Electron再发布,不然会出现某知名在线教育机构的Electron桌面应用,发布到客户电脑上,报错。
咳咳咳,具体是哪家,就不提了,咱也不知道,咱也不敢说。
后记
写到这里,只是想给对Electron感兴趣的小伙伴,一个冷静的分析,自己所在的团队,是否能撑得起这套框架的成本,看得见的便利性是存在的,看不见的隐藏成本,是否可以为此买单。
肯定会有很多微软狂热粉 VS Code也用的Electron啊!
实际上对于那种技术研发的大型公司,用什么技术,已经不再是难题了,选择了Electron,也只是为了拥抱社区做的妥协,并不代表这个技术的选型是最佳方案。
技术的选择依旧是 自己的团队是否可以承担简单功能外的Node原生的编写和实现。
Electron入门指北的更多相关文章
- Python 简单入门指北(二)
Python 简单入门指北(二) 2 函数 2.1 函数是一等公民 一等公民指的是 Python 的函数能够动态创建,能赋值给别的变量,能作为参传给函数,也能作为函数的返回值.总而言之,函数和普通变量 ...
- Python 简单入门指北(一)
Python 简单入门指北(一) Python 是一门非常容易上手的语言,通过查阅资料和教程,也许一晚上就能写出一个简单的爬虫.但 Python 也是一门很难精通的语言,因为简洁的语法背后隐藏了许多黑 ...
- 关于supervisor的入门指北
关于supervisor的入门指北 在目前这个时间点(2017/07/25),supervisor还是仅支持python2,所以我们要用版本管理pyenv来隔离环境. pyenv 根据官方文档的讲解, ...
- Celery入门指北
Celery入门指北 其实本文就是我看完Celery的官方文档指南的读书笔记.然后由于我的懒,只看完了那些入门指南,原文地址:First Steps with Celery,Next Steps,Us ...
- Angular 从入坑到挖坑 - Router 路由使用入门指北
一.Overview Angular 入坑记录的笔记第五篇,因为一直在加班的缘故拖了有一个多月,主要是介绍在 Angular 中如何配置路由,完成重定向以及参数传递.至于路由守卫.路由懒加载等&quo ...
- SourceGenerator入门指北
SourceGenerator介绍 SourceGenerator于2020年4月29日在微软的.net blog首次介绍,大概说的是开发者编可以写分析器,在项目代码编译时,分析器分析项目既有的静态代 ...
- 后端API入门到放弃指北
后端API入门学习指北 了解一下一下概念. RESTful API标准] 所有的API都遵循[RESTful API标准]. 建议大家都简单了解一下HTTP协议和RESTful API相关资料. 阮一 ...
- 关于Gevent的使用指北
关于Gevent的使用指北 只是看了入门指南,和一个翻译文档.写一下个人读书心得. 其实看完之后,第一个反映就是asyncio这个系统库,感觉gevent现在所做的一些事情是与asyncio很像的,但 ...
- 颓废选手在 Ubuntu/Noilinux 下的生存指北
颓废选手在 Ubuntu/Noilinux 下的生存指北 Hint: 这里的 "#" 都是假注释,复制的时候记得删除 一些基本的生存命令 ctrl + alt + t #调出终端 ...
随机推荐
- NOIP提高组2016 D1T2 【天天爱跑步】
码了一个下午加一个晚上吧...... 题目描述: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成 ...
- 配置DVWA漏洞环境
web萌新,因为在别人的环境上练习总有点不舒服,所以在本地搭建了网站:下面记录一下搭建的步骤 DVWA:是一个漏洞环境包,可以用phpstudy或者wamp解析:所以要想配置这个环境,就必须有这两个软 ...
- 面试题____pthon__002(法本_) 阿里
1.描述一下您负责的业务中最复杂的业务(可以从业务是为了解决用户的什么问题切入).这个最复杂的业务中,最复杂的模块是什么,这个模块的主要功能详细描述一下.这个模块,采用了什么样的测试手段保障质量?2. ...
- 多测师_高级讲师肖sir讲解html中 Button跳转连接方法归纳
第一种方法: 1.1<a href="http://www.baidu.com"> <input type="button" name=& ...
- JAVA Schedule的Cron表达式
spring中用到的定时任务,一般用到的有Timer()和Schedule Cron表达式一般是程序的定时任务中所要起的..我们用的springboot中的@Schedule中,启动类中添加enabl ...
- 适合刚刚学习编程的萌新:C语言编程学习制作超简单又好玩的报数游戏!
C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...
- Linux系统编程—信号捕捉
前面我们学习了信号产生的几种方式,而对于信号的处理有如下几种方式: 默认处理方式: 忽略: 捕捉. 信号的捕捉,说白了就是抓到一个信号后,执行我们指定的函数,或者执行我们指定的动作.下面详细介绍两个信 ...
- go panic
panic 抛出异常 通过recover捕获 类似 php python等语言的try catch package mainimport ( "fmt" "errors& ...
- 浏览器页面左上角出现undefined
浏览器页面左上角出现undefined, js文档中: let list; list += html代码; 解决办法: let list = html代码;
- CentOS 8 Yum安装ansible
ansible的安装 直接yum安装ansible会报错,需要先安装epel源. ansible的安装来源于epel仓库,因此在安装前需确保安装了正确的epel源. yum install -y ep ...