基于 Umi 的 Electron React 框架
您可以快速构建一个 Electron 项目,可以开发、打包、升级等,它具备 Umi 的所有功能。它还集成了常用的 electron 库,比如:electron-log 、electron-store... 未来还将集成更多功能。
先找个地方建个空目录。
$ mkdir myapp && cd myapp
# pnpm 推荐
$ pnpm create poros
# npm
$ npx create-poros@latest
# yarn
$ yarn create poros
执行 pnpm start
命令
╔═══════════════════════════════╗
ready - ║ Electron app launch success ║
╚═══════════════════════════════╝
event - [Webpack] Compiled in 19830 ms (4955 modules)
info - [MFSU][eager] write cache
info - [MFSU] buildDepsAgain
info - [MFSU] skip buildDeps
├── config
│ ├── builder.ts // electron-builder 配置
│ ├── config.ts // umi 配置
│ └── routes.ts // umi routes 配置
├── mock
│ └── demo.ts
├── src
│ ├── constants
│ │ └── index.ts
│ ├── locales // 国际化目录,开启国际化插件有效
│ │ ├── en-US.ts
│ │ └── zh-CN.ts
│ ├── main // 主进程目录
│ │ ├── windows // 窗口目录
│ │ └── index.ts
│ ├── preload // preload 目录
│ │ └── index.ts
│ ├── renderer // 渲染进程目录,同 umi
│ │ ├── assets
│ │ ├── models
│ │ ├── pages
│ │ ├── utils
│ │ ├── ipc.ts // 渲染进程与主进程 ipc 通信定义文件,开启 ipc 插件有效
│ │ └── app.ts
├── package.json
├── pnpm-lock.yaml
├── tsconfig.json
└── typings.d.ts
框架约定以 src/main/window
目录作为自定定窗口目录
自定义窗口需要继承
PorosBrowserWindow
类,PorosBrowserWindow
为BrowserWindow
子类
// src/main/window/MainWindow
import path from 'path';
import { PorosBrowserWindow, PorosBrowserWindowOptions } from 'poros';
class MainWindow extends PorosBrowserWindow {
/**
* 是否单例, 默认:true
*/
static readonly single = true;
/**
* 加载页面地址
*/
protected static readonly URL = '/';
/**
* 窗口属性配置
*/
protected static readonly OPTIONS: PorosBrowserWindowOptions = {
title: 'Poros',
height: 628,
width: 542,
minHeight: 628,
minWidth: 542,
hideOnClose: true,
webPreferences: {
preload: path.join(__dirname, 'preload/index.js'),
},
};
constructor() {
super(MainWindow.URL, MainWindow.OPTIONS);
}
protected registerWindowEvent(): void {}
}
export default MainWindow;
import { something } from 'poros';
参数 | 类型 | 说明 |
---|---|---|
initialize | () => void | 初始化方法,需要在 app ready 之前调用 |
PorosBrowserWindow | PorosBrowserWindow | 窗口基类 |
PorosWindowManager | PorosWindowManager | 窗口管理类 |
port | number | dev web 服务端口 |
logger | Logger | 日志模块 |
localStore | LocalStore | 本地化存储,可以本地文件的方式存储一些配置信息 |
localShortcut | LocalShortcut | 窗口化快捷键 |
isMacOS | boolean | 是否为 macOS 系统 |
isWindows | boolean | 是否为 Windows 系统 |
isLinux | boolean | 是否为 Linux 系统 |
isX86 | boolean | 是否为 x86 架构 |
isX64 | boolean | 是否为 x64 架构 |
isDev | boolean | 是否为开发环境 |
isProd | boolean | 是否为生产环境 |
透传
umi
的所有属性, 也加入了一些写的属性
参数 | 类型 | 说明 |
---|---|---|
logger | Logger | 日志模块 |
localStore | LocalStore | 本地化存储,可以本地文件的方式存储一些配置信息 |
继承至 BrowserWindow
参数 | 类型 | 说明 |
---|---|---|
single | static readonly boolean | 是否单例, 默认:true |
URL | static readonly string | 加载页面地址 |
OPTIONS | static readonly PorosBrowserWindowOptions | 窗口配置项 |
registerWindowEvent | () => void | 注册窗口事件 |
管理 PorosBrowserWindow
窗口
参数 | 类型 | 说明 |
---|---|---|
create | (constructor: Type<PorosBrowserWindow>, ...properties: ConstructorParameters<typeof constructor>) => PorosBrowserWindow | 创建窗口实例 |
destroy | (id: number) => void | (constructor: Type\<PorosBrowserWindow\>) => void |
销毁窗口实例 |
destroyAll | (excludes: Type<PorosBrowserWindow>[] = []) | 销毁所有窗口实例,excludes:排除项 |
getAll | () => PorosBrowserWindow[] | 获取所有窗口 |
get | (constructor: PorosBrowserWindow) => PorosBrowserWindow\|Record<number, PorosBrowserWindow>\|undefined | (id: number) => PorosBrowserWindow\|undefined |
获取窗口 |
配置项 config/config.ts
export default defineConfig({
logger : {
transports: {
file: {
level: 'warn',
format: '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}]{scope} {text}',
maxSize: 1048576,
},
console: {
level: 'debug',
},
},
}
});
具体配置和用法可参照electron-log。
注意:控制台的日志输出为了作出类型区分加了特有的标志,所有
transports.console.format
的设置不会生效,
保存用户设置、应用程序状态、缓存等
配置项 config/config.ts
export default defineConfig({
localStore: {
schema: {
unicorn: {
type: 'string',
default: '🦄',
},
},
},
});
具体配置和用法可参照electron-store。
将键盘快捷键本地添加到 BrowserWindow 实例,而不使用菜单
PorosBrowserWindow
中内置了打开 DevTools 快捷键 Cmd+Option+I
或 F12
具体用法可参照electron-localshortcut。
您也可以直接使用 Umi 插件。如果您遇到任何问题,请联系我。
与 umi locale 插件功能基本相同,开启方法一致,主进程与渲染进程中使用方法相同。
import { localeInfo, getIntl, setIntl, getLocale, setLocale, getAllLocales, i18n } from 'poros';
i18n('button.ok');
参数 | 类型 | 说明 |
---|---|---|
localeInfo | {[key: string]: {messages:{[key: string]},locale:string}} | 语言信息 |
getIntl | (lang?: string, changeIntl?: boolean) => IntlShape | 日获取当前的 intl 对象志模块 |
setIntl | (lang: string) => void | 切换全局的 intl 的设置 |
getLocale | () => string | 获取当前选择的语言 |
setLocale | (lang: string) => void | 设置语言 |
getAllLocales | string[] | 获取多语言列表 |
i18n | (id:string, values?: Record<string, any>) => string | formatMessage 语法糖 |
简化主进程与渲染进程之间的通信
参数 | 类型 | 说明 |
---|---|---|
IpcHandle | - | ipc 方法注解,PorosBrowserWindow 内使用 |
rendererInvoker | {[method: string]: (...args:any[], opts?: { broadcast?: boolean, window?: PorosBrowserWindow})} | 渲染进程方法调用器 |
rendererInvoker
中 broadcast
为 true
时,会给所有窗口广播事件(广播事件无返回值),所有监听了事件的窗口都会收到消息,反之只有相应的窗口下页面会收到消息。PorosBrowserWindow
类中调用,window 默认值为当前窗口,非PorosBrowserWindow
类中必需指定 window 值。
参数 | 类型 | 说明 |
---|---|---|
useIpc | (channel: string ,callback?:(...args:any[])=>any)=>any[] | ipc 方法注解,PorosBrowserWindow 内使用 |
mainInvoker | {[windowName: string]: {[method: string]: (...args:any)=>any}, open: ()=>void} | 主进程方法调用器 |
// 1 、使用 IpcHandle 注解要调用的方法
import { IpcHandle } from 'poros';
class MainWindow extends PorosBrowserWindow {
// ... 省略基本属性
@IpcHandle
foo(name: string) {
return 'Hello renderer'; // 返回给渲染进程
}
}
export default MainWindow;
// 2 、渲染进程中调用
import { mainInvoker } from 'poros';
const ret = mainInvoker.MainWindow.foo('demo');
1 、定义事件类型(/src/renderer/ipc.ts)
export default interface IpcChannelToHandlerMap {
'network-monitor': (received: number, transferred: number) => string;
}
2 、react 组件中监听
import { mainInvoker } from 'poros';
const Demo = () => {
useIpc('network-monitor', (received, transferred) => {
return ''; // 返回值给主进程
});
// 或者
const [received, transferred] = useIpc('network-monitor');
return (
<div>demo</div>
);
};
export default Demo;
3 、主进程中调用
// PorosBrowserWindow 类中调用
const ret = this.rendererInvoker.networkMonitor(received: number, transferred: number, opts?: { broadcast?: boolean, window?: PorosBrowserWindow});
// 非 PorosBrowserWindow 类中调用
import { rendererInvoker } from 'poros';
rendererInvoker.networkMonitor(received: number, transferred: number, opts: { broadcast?: boolean, window: PorosBrowserWindow });