我是如何实现electron的在线升级热更新功能的?

这篇文章发布于 2017年06月27日,星期二,23:22,归类于 JS相关。 阅读 76923 次, 今日 8 次 27 条评论

 

通常electron打包出来的文件都很大,有40~50M,如果每次改动升级都要下载个完整版本,实际上是很烦的。

实际上,只要主线程没有发生变化,我们是可以直接在线热更新我们的electron应用的。

一、electron的热更新效果预览

下面几张图是我实现的带热更新功能的electron应用实际效果截图:

打开electron应用,此时会去检测线上是否有新版本,例如,我本地版本是1.2.2,然后线上版本是1.2.4,则会有这样的显示:

可升级提示效果

点击“新版功能”会显示最新版的升级描述,例如,这里点击后出现弹框信息:

新版功能弹框说明截图

点击红色的“升级”按钮,则直接请求线上的资源替换本地资源,完成升级(升级成功后刷新页面),升级效果参见下gif截图:

升级效果实时gif截图效果

二、electron的热更新原理说明

1. 我是直接使用github作为线上资源仓储的

当使用raw.githubusercontent.com作为请求域名,我们是可以直接获取资源内容的,例如,我们要获取一个路径为js/test.js的文件,则该文件完整地址为:

https://raw.githubusercontent.com/username/project-name/master/js/test.js

此时,我们就可以使用node.js的https.get()方法获取这个js/test.js完整内容了。

2. 我是借助package.json标记版本和更新内容的

之所以借助package.json,主要是被里面约定俗成的version版本关键字吸引,如果用户本地version版本比github项目线上version版本低,岂不就意味着可以进行升级。

于是,再把升级文件列表和更新信息一整合,就有了完整的升级数据了,如下截图示意:

升级描述和升级版本信息截图示意

3. electron的热更新原理说明

当每次我们的electron加载完毕之后,就会发送一个请求,去获取github项目上的package.json文件,主要是知道目前线上的版本是多少,然后和本地的package.json文件的version版本数据做比较。如果发现版本不一致,则说明有新版可以升级,于是让界面变成这样:

可升级提示效果

当我们点击“升级”按钮后,会把高于本地版本的需要更新的文件重新整合成一个新的完整的升级文件列表,然后依次从github上远程获取,存储在一个临时文件夹中,如果全部文件获取成功,再一并覆盖本地资源,全部覆盖完成后,刷新页面,完成升级。

以上就是完整的升级原理。

三、electron的热更新一些代码实现

electron热更新最大的难点应该是如何获取远程资源,我简单整理了下,希望能够对有需求的小伙伴有所帮助,由于ES6并未花时间学习,因此,相关JS还是ES5语法:

var https = require('https');

var getHttpsData = function (filepath, success, error) {
  // 回调缺省时候的处理
  success = success || function () {};
  error = error || function () {};

  var url = 'https://raw.githubusercontent.com/username/project-name/master/' + filepath + '?r=' + Math.random();

  https.get(url, function (res) {
    var statusCode = res.statusCode;

    if (statusCode !== 200) {
        // 出错回调
        error();
        // 消耗响应数据以释放内存
        res.resume();
        return;
    }

    res.setEncoding('utf8');
    var rawData = '';
    res.on('data', function (chunk) {
      rawData += chunk;
    });

    // 请求结束
    res.on('end', function () {
      // 成功回调
      success(rawData);
    }).on('error', function (e) {
      // 出错回调
      error();
    });
  });
};

然后,下面的事情就简单了,直接把请求的数据写入本地就可以了,举个简单的例子,一个index.html文件:

getHttpsData('index.html', function (data) {
  // 写入文件
  fs.writeFileSync('index.html', data);
  // 然后下一个文件获取并写入...
});

配合一些loading交互效果,就完成了完整的在线热更新功能。

四、结束语

上周六的作为嘉宾参见了腾讯2017 TFC前端大会,其中不少分享主题内容其实是不错的,但是效果却一般。主要在于犯了下面几个大型分享常见错误:
1. PPT文字小多,放置大段的代码,在大型会议场合,后排的根本就看不到内容,因此,只能玩手机,这和平时在团队或者学院内分享是不一样的;
2. 分享内容为中规中矩的流水陈述,大型分享和晋升汇报不一样,应该像电影一样,通过可以制造冲突和巧妙的内容剪辑,让分享更有吸引力,否则长途奔波+早起的听众很容易打瞌睡;
3. 一些不适用于大型分享的小技巧,例如,请问如何如何请举手,如果是中小型分享,或者当前氛围不错,这些技巧有助于增加互动,但是在如此宽广的场地,以及大多人听众不是很专注的情况下,这种策略就略显尴尬,因为一个问题出来会没有预想的互动场景出现。因此尽可能通过单向的肢体,语调,措辞以及干货的内容展示自身风采才是上策。

最后,奉上帅照一张:

(本篇完)

分享到:


发表评论(目前27 条评论)

  1. 名称说道:

    说真的直接 mainWin.loadURL() 能解决90%的场景 因为需要离线的场景真的非常少 都没网络了 就算能打开应用也没啥用 不如直接提示用户

  2. 大米说道:

    博主这个只能更新未打成asar的electron客户端

    对打包成asar的客户端热更新需要一个叫electron-asar-hot-updater的模块
    这个模块C#写的,可以编译成独立的应用程序再由electron调用

  3. @li说道:

    webpack 编译后的资源,热更新咋整呢?

    electron + Ant Design Pro 开发的,打出的 app 有 600M+,遇到了热更新的需求。

  4. sai说道:

    你好,能否在GitHub上开源呢

  5. 资源型的文件说道:

    这种资源型的文件,直接用 mainWindow.loadURL(‘…’) 不是更好?
    资源文件里用node 接口也没问题。。。

    • yiyi说道:

      好像很有道理的样子,将这些静态资源放在 CDN 里也是可以的。不过这就要求 Electron 应用是必须联网的,主要看应用场景。

  6. xcsweb说道:

    很好啊

  7. 小哥儿说道:

    写入权限没有怎么解决?

  8. SHAO说道:

    请问如果打包成asar文件还能使用热更新么?

  9. 陈磊说道:

    fs.writeFileSync(‘index.html’, data);
    如果无权限写入,这个应该如何处理

  10. jyp说道:

    如果打包成asar文件还能使用这种方法么?

  11. 氵点水说道:

    原来上次我距离大神这么近 我却看不到 日哦

  12. 起点终站说道:

    路过支持下。。。。

  13. 清凌渡说道:

    我的方案是:

    程序打包后发布到GitHub,然后配合Nuts实现自动更新。
    GitHub 支持不同channel, 并且也可以查询更新日志,管理版本非常方便

    如果是用electron-builder打包,目前最新版本也支持从s3等静态托管服务 更新

  14. alphabet007说道:

    小白前来膜拜

  15. 舞颢说道:

    为什么没用mainWindow.loadURL(“http://www.apps.com/”),是出于某方面的考虑么?

  16. chenxuan说道:

    赞同最后的结束语。
    博主心里肯定想大多数分享主题都挺无聊的。

  17. pale说道:

    博主,身高多少啊,看着好高的样子

  18. 逆蝶说道:

    蛮好的,羡慕

  19. 松鼠说道:

    去参加 TFC,就冲着你去的,以为张大神会分享一点东西…..后来结束的时候拍照也没找到你….尴尬….错过了和张大神合影的机会

  20. DH说道:

    图示是什么应用呢,能否开源学习一下?