查看原文
其他

Electron 12 和 13 新特性介绍

与天 淘系前端团队 2021-07-10

最新的 Electron 正式版本是 13-x-y,这次 Electron 本身提供的新能力比较少,但 Node 升级到了 14.16.0,并且 v8 升级到了 9.1,现在一起看看 Elecron 12 及 13 新增了哪些特性吧。

一、Electron 13 特性介绍

Electron 值得说的特性

1. 添加一个圆角的选项

初始化 BrowserWindows 的时候,新增 roundedCorners 选项,支持在 frameless 的窗口能直角。常用于托盘,或者小窗的场景,比如下面这种效果,顶部的两个角都是直角。

image.png

2. 模块 session 增加 storagePath 属性

这个功能在使用拦截器的时候常常使用,比如使用 fromPartition 加上 persist 开头的字符串,就会在本地生成一个有名的 session 存储文件夹 abc:

image.png

里面包括了 Code Cache 以及 Local Storage 之类的缓存(后面会讲到也包括插件):

image.png

3. 部分接口进行了转移

  • 插件 API 之前挂在 BrowserWindows ,现在部分移植到了 session 中。sess.loadExtensionses.getAllExtensions()
  • systemPreferences 模块关于暗黑模式,高对比度颜色相关的接口移植到 nativeTheme.shouldUseDarkColors 这类模块中,具体可以直接看 nativeTheme 模块即可

Node.js 值得提的特性

Node.js 已经升级到 14.16.0,到目前为止比较想提的就两个,一个是现在 fs 模块支持 promise api 调用了,比如下面这个 ensureDir 方法,实现起来就不需要用 promisify 包裹一层。

import fs, { promises as fsPromises, PathLike } from 'fs';

export async function ensureDir(dirPath: PathLike) {
  try {
    await fsPromises.mkdir(dirPath, { recursive: true });
  } catch (error) {
    if (error.code !== 'EEXIST') {
      throw error;
    }
  }
}

二是 fs 模块支持 fs.rm 和 fs.rmSync ,这是一个 Node.js 14.14.0 新增的特性,参数可以是文件或者文件夹,使用起来会很方便。

V8 的一些新特性

  1. 顶层默认支持 await 语法
await fetch('https://example.com')
  1. 类中的私有变量默认支持用于 #var in obj语法
class A {
  static test(obj) {
    console.log(#foo in obj);
  }

  #foo = 0;
}

A.test(new A()); // true
A.test({}); // false

二、Electron 12 特性介绍

12.x 的版本 Electron 自身的特性偏多,关于 Node.js 相对就少了。

1. 新增 net 模块 isOnline 方法

文档:isOnline 不需要创建 BrowserWindow 获取 navigator.onLine ,就知道当前网路环境的接口 net.isOnline() 。

image.png

这个接口的实现是基于 chromium 内核的,也就是说虽然显示了是连线,只能说网卡显示了连线,到底能不能联网,还要看其它的网络因素。

2. 隔离模式 contextBridge

文档:API context-bridge在配置 contextIsolation: true 后,可以通过 contextBridge.exposeInMainWorld 暴露想要的变量或者方法,比如下面:

// main.ts
const mainWindow = new BrowserWindow({
  height: 600,
  width: 800,
  webPreferences: {
    contextIsolation: true,
    preload: path.join(__dirname, './preload.js'),
  },
});


// preload.ts (Isolated World)
const { contextBridge, ipcRenderer } = require('electron');

// 简单赋值
(window as any).hello = 'yutian hello';

// 暴露特殊变量
console.log('print contextBridge', contextBridge);
contextBridge.exposeInMainWorld(
  'electron',
  {
    doThing: () => ipcRenderer.send('do-a-thing')
  }
)

最后在 DevTools 中能看到, 可以直接访问 window.electron.doThing() ,但 window.hello 是不能访问到的:

image.png

当然这些方法因为已经被隔离了,所有支持的类型都是固定和有限的,具体的支持类型在这里:Type Support(https://www.electronjs.org/docs/api/context-bridge#parameter--error--return-type-support


3. WebContents 新的 API webFrameMain

webFrameMain 是主进程 WebContents 新增的一个属性,用于查找和监听渲染进程的 frame,并且对其进行控制。之前有 webFrame 这个属性,但这个是用在渲染进程的,在主进程操作就不会方便,所以新增了一个。

const { BrowserWindow } = require('electron')
async function main () {
  const win = new BrowserWindow({ width800height600 })
  await win.loadURL('https://reddit.com')
  const youtubeEmbeds = win.webContents.mainFrame.frames.filter((frame) => {
    try {
      const url = new URL(frame.url)
      return url.host === 'www.youtube.com'
    } catch {
      return false
    }
  })
  console.log(youtubeEmbeds)
}
main()

4. MenuItem

增加 macOS 的分享菜单:

image.png
const menu = Menu.buildFromTemplate([
  { role'windowMenu' },
  {
    role'shareMenu',
    sharingItem: {
      urls: [ 'https://github.com/electron/electron/issues/6330' ]
    }
  },
])
menu.popup(win)

也可以直接弹出分享菜单:

const menu2 = new ShareMenu({
  filePaths: [ __filename ]
})
menu2.popup(win)

5. 删除文件使用异步 shell.trashItem()

废弃同步方法调用 shell.moveItemToTrash() ,下面是有人做的测试,说用同步方法 moveItemToTrash 在渲染进程调用比通过 IPC 在主进程调用,会花费很多时间。可以看出,在渲染进程做一些系统级别的操作应该挺花时间的 (这个并没有表示用 shell.trashItem 会快):

Renderer:
delete-sync: 493.988037109375ms
delete-sync: 562.8349609375ms
delete-sync: 609.74609375ms

Calls to main via IPC:
delete-async: 0.156982421875ms
delete-async: 0.13916015625ms
delete-async: 0.172119140625ms

另外一个好处是,不管是什么情况,同步调用都会导致整个应用程序卡住,而异步不会。

之前 Electron 8.x 9.x 版本,同样对 shell 模块的 shell.openExternal 也进行了异步改造,但名字没改。

6. spellcheck 模块新方法

新增:webFrame.isWordMisspelled(word) 和 webFrame.getWordSuggestions(word) 。应该可以不用第三方 spellcheck 库了。

7. net 模块新属性

  • credentials 这个应该很常见,就是 fetch 规范 options 的一个属性,现在增加到了 new ClientRequest(options) 中,提供更全的应用场景。
  • useSessionCookies 这个属性也添加到了 new ClientRequest(options) ,用来获取当前 Session 的 cookies,然后附带这个信息发送出去。值得一提的是,我们可以直接获取 cookies 的信息:
const sess = session.defaultSession;const [cookie] = await sess.cookies.get({ name: 'SessionId' });if (cookie && cookie.expirationDate) {  console.log('cookie expiration date', cookie.expirationDate);}

8. Breaking Changes

1. 正式禁用 Remote 模块

使用一个新的包 [@electron/remote](https://github.com/electron/remote) 替代

2. contextIsolation 和 worldSafeExecuteJavaScript 默认值变为 true

Electron 12 现在默认开启 contextIsolation 。就是开启隔离模式,之后 preload 脚本的变量和方法都不能穿透到 renderer 进程。

3. 去掉 Flash 支持

其它

  • 停止支持 Electron 9.x 以及 10.x。Electron 发布时间线(https://www.electronjs.org/docs/tutorial/electron-timelines
  • 更全面的更新信息在这里 Electron stable(https://www.electronjs.org/releases/stable

可以从 Electorn 12 到 13 这一系列的版本中的 API 演进,看得出 Electron 在安全方面越来越重视,特别是 Electron 12 完善了非常多的隔离网页的接口,比如 contextBridge、session 和 contextIsolation,同时在这个版本中 Node.js 的升级也提供了非常多的安全更新。Electron 13 就升级了非常多 Node.js 相关的特性,而自身就没有太多更新。这样循序渐进的迭代版本非常适合这种场景,更加稳定。


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存