Electron 12 和 13 新特性介绍
最新的 Electron 正式版本是 13-x-y,这次 Electron 本身提供的新能力比较少,但 Node 升级到了 14.16.0,并且 v8 升级到了 9.1,现在一起看看 Elecron 12 及 13 新增了哪些特性吧。
一、Electron 13 特性介绍
Electron 值得说的特性
1. 添加一个圆角的选项
初始化 BrowserWindows 的时候,新增 roundedCorners 选项,支持在 frameless 的窗口能直角。常用于托盘,或者小窗的场景,比如下面这种效果,顶部的两个角都是直角。
2. 模块 session 增加 storagePath 属性
这个功能在使用拦截器的时候常常使用,比如使用 fromPartition 加上 persist 开头的字符串,就会在本地生成一个有名的 session 存储文件夹 abc:
里面包括了 Code Cache 以及 Local Storage 之类的缓存(后面会讲到也包括插件):
3. 部分接口进行了转移
插件 API 之前挂在 BrowserWindows ,现在部分移植到了 session 中。 sess.loadExtension
、ses.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 的一些新特性
顶层默认支持 await 语法
await fetch('https://example.com')
类中的私有变量默认支持用于 #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()
。
这个接口的实现是基于 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
是不能访问到的:
当然这些方法因为已经被隔离了,所有支持的类型都是固定和有限的,具体的支持类型在这里: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({ width: 800, height: 600 })
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 的分享菜单:
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 的一个属性,现在增加到了 newClientRequest(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 相关的特性,而自身就没有太多更新。这样循序渐进的迭代版本非常适合这种场景,更加稳定。