关于 Node 集成
页面在 Electron 中和在浏览器中的一个区别是:Electron 窗口中可以使用 Node API。
在 Electron 中的窗口,可自行决定是否开启 Node 集成。开启和不开启 Node 集成,在我们开发代码组织上有一点差异。当然也有各自的好处,我们推荐使用:窗口中关闭 Node 集成的形式进行开发,这种方式能够更安全,也是 Electron 主推的一种方式。
窗口中关闭 Node(推荐)
关闭 Node之后,我们可以通过 Electron 官方推荐的 contextBridge.exposeInMainWorld
,将 Node 相关功能注入到页面中。
Electron 窗口的配置中存在一个 preload
配置,用于配置在页面加载之前需要加载的脚本。称作:预加载脚本。
补充信息
当我们关闭了窗口的 Node 配置时,我们不可以在页面中直接使用 Node 相关 API,但可以在预加载脚本中使用。
再通过 Electron 提供的 contextBridge.exposeInMainWorld
方式注入到 window
上。从而我们可以在页面中,通过这种方式使用 Node API。
// Preload (Isolated World)
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
);
// Renderer (Main World)
window.electron.doThing();
因此,框架也使用了这种方式来进行开发,具体流程如下:
预加载脚本中注册相关功能服务。
上面说到,Electron 官方示例中关于预加载脚本的使用。我们新建
electron/preload
目录,并新建:electron/preload/index.tsimport {
exposeInMainWorld,
browserWindowPreloadApis,
} from '@modern-js/runtime/electron-render';
import { readFileSync } from 'fs';
export const apis = {
...browserWindowPreloadApis,
readFileSync: (path: string) => {
return fs.readFileSync(path);
},
};
exposeInMainWorld(apis);上述代码中,我们在预加载脚本中定义了
readFileSync
方法,并通过exposeInMainWorld
注册到了window
上。我们可以在窗口打开的时候注入预加载脚本。在这之前,我们可以新建一个
index.dev.js
, 通过 Babel 编译解决 TS 或者一些语法编译问题:index.dev.jsconst { join } = require('path');
const babel = require('@babel/register');
const { babelConfig } = require('@modern-js/electron-tools');
babel(
Object.assign(babelConfig, {
extensions: ['.ts', '.js'],
}),
);
require(join(__dirname, 'index.ts'));然后,我们在窗口配置中,增加预加载脚本文件地址:
electron/main.ts// preload js for browserwindow to provide native apis for render-process
const PRELOAD_JS = join(
__dirname,
'preload',
process.env.NODE_ENV === 'development' ? 'index.dev.js' : 'index.js',
);
const runtime = new Runtime({
windowsConfig: [{
name: 'main',
options: {
webPreferences: {
preload: PRELOAD_JS,
},
},
}],
mainServices: services
});渲染进程中使用服务。
我们通过预加载脚本注入了服务之后,可以通过如下方式在渲染进程中访问:
import bridge from '@modern-js/runtime/electron-bridge';
。但这样,我们需要有类型提示,因此可以新建类型提示文件:
typings/index.d.tsdeclare module '@modern-js/electron-runtime' {
export type BrowserWindowApis = typeof import('../electron/preload').apis;
}并在项目根目录
tsconfig.json
中配置"types": ["./typings"]
:{
"compilerOptions": {
...
"types": ["./typings"]
},
...
}即可:
窗口中开启 Node
提示
启用 Node 后,我们可以在其加载的页面上直接使用 Node 相关 API,比如:Node 能力,Electron 原生 API。
窗口开启 Node。
在前面讲解到的窗口配置中,增加:
nodeIntegration: true
, 开启 Node 环境。export const windowsConfig: WindowConfig[] = [
{
name: 'main',
options: {
webPreferences: {
nodeIntegration: true,
...
},
},
},
]渲染进程支持 Node API。
dev
启动命令增加:modern dev electron-web
,从而在 webpack-dev-server 编译的时候,增加相应 Webpack 配置。 从而可以使用 Node。// package.json#scripts
"dev:render": "modern dev electron-web"渲染进程中直接使用 Node API。
xx/xx.tsximport * as fs from 'fs';
...
fs.readFileSync('xx/xxx.txt');
警告
使用这种模式,必须开启窗口的 Node 能力。