惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
T
The Blog of Author Tim Ferriss
U
Unit 42
Microsoft Security Blog
Microsoft Security Blog
WordPress大学
WordPress大学
Vercel News
Vercel News
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
Blog — PlanetScale
Blog — PlanetScale
I
InfoQ
Y
Y Combinator Blog
F
Full Disclosure
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
Google Developers Blog
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
博客园 - 叶小钗
S
SegmentFault 最新的问题
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
Recent Commits to openclaw:main
Recent Commits to openclaw:main
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
F
Fortinet All Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
Hugging Face - Blog
Hugging Face - Blog
T
Threatpost
GbyAI
GbyAI
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
L
LangChain Blog
T
Tenable Blog
C
Cisco Blogs
T
Threat Research - Cisco Blogs
Google Online Security Blog
Google Online Security Blog

Electron

用 Puppeteer 给掘金写了个自动发图文的工具,顺手做成了 CLI 和 MCP 接口 electron-vite 创建的项目,经 preload 挂载的 api 在浏览器中打印出来是 undefined,有人遇到过吗? - V2EX 十年前开发的 elctron 应用至今完美运行,十年后的 tauri 应用可以吗? - V2EX 用什么来管理 Electron App + better-sqlite3 的? - V2EX 请教问题,接触 Electron 开发不久,如何便捷的在不同版本系统\硬件设备上方便测试程序 - V2EX mac 程序签名公证问题 - V2EX elctron 开发教程案例解析:模拟真人使用“高德地图”,节省数据 API 采购费用 - V2EX electron 怎么开启独立窗口而不增加渲染进程? - V2EX electron 项目打包成 exe, windows10 安装后打开不了。一直提示缺少快捷方式。有没有大佬遇到过类似的问题 - V2EX electron 新开独立窗口内存问题 - V2EX 求助!双显卡连接 6 个屏幕,展示不同的 URL 页面。Electron 的 displayId 每次重启都会变 - V2EX Electron 热更新技术 - V2EX 如何自己实现类似 c-Lodop 的不中断打印效果? - V2EX 朋友们,你们公司的 Electron 项目用什么做数据统计? Google Analytics 可以用吗? - V2EX 关于 electron,问一个关于查找的问题 - V2EX electron 开发:单独的 VUE 工程和单独的 electron 工程想通信怎么处理? - V2EX 萌新求教, Electron 在请求跨域的接口时,怎么获取 cookie? - V2EX 求教! electron 开发的工具类客户端应用如何设计激活机制? - V2EX [求助] Electron 中运行 Webassembly 疑问 - V2EX 寻求有偿帮助,将 Electron 应用上架至 Mac App Store。 - V2EX Electron 开发的 Windows 桌面应用打开时为什么有一个 installing 的窗口? - V2EX electron mac store 应用签名上架求助 - V2EX Win10 下通过 npm 安装 electron 出现报错 - V2EX mac 如何监听软件变化 - V2EX electron 内存优化 - V2EX 请教一下, electron 打包的安装包,包含的 bin 文件无法执行问题 - V2EX 有 Flutter 就行了为什么还需要 Electron,谁来纠正一下我的想法 - V2EX 趁着这把 AI 炒作, Eletron 有没有更火了? - V2EX electron 启动时如何取消 update 窗口 - V2EX 再也不说 electron 是个邪恶的技术了 - V2EX Electron+Nest.js 打工人的偷懒架构 - V2EX Electron 如何实现类似微信通过另外的 exe 应用打开小程序? - V2EX 请问有没有 Electron 的脚手架工程 - V2EX 请教 Nextjs 与 Electron 的可行性 - V2EX Windows 上 Electron 类 app 卡死问题(比如 vscode、tabby) - V2EX electron 和 Java swing 开发出的软件 哪个体验好 - V2EX 哪一个 electron 打包工具是把多平台的 native modules 与业务逻辑 app 彻底隔开的,,这样三平台,只需要安装该平台的 electron,然后发布一个统一的 app.asar 或 app source 就可以 - V2EX 内嵌浏览器(CEF)有时会崩溃白屏。如何在崩溃时,保存一份 JS 和 DOM 堆内存快照呢? - V2EX 今年写的第一本 Electron 课程上线啦,欢迎来捧场🎉 - V2EX electron svg 会保留 ‘痕迹’ - V2EX 后端学习 Electron,有没有好的开源项目用来学习一下? - V2EX 对 electron 系软件的无响应问题实在是烦不胜烦,不知道何时才能解脱 - V2EX electron 思路求助 - V2EX 向前端大佬们请教一下关于 electron 调用 native 方面的问题 - V2EX electron 失焦 系统休眠后定时器停止问题 - V2EX Lossless-Cut 这个 repo 谁能帮我看看 - V2EX 大佬们 最近在学 electron 有没有推荐的练手项目 - V2EX 请问: 如何把 chatGpt 整合到 electron 项目中? - V2EX Electron 集成 firebase - V2EX 想用 Electron 做一个截图小工具,似乎第一步打开窗口就有点问题? - V2EX
Poros-基于 Umi 的 Electron React 框架 - V2EX
Minimx · 2024-04-25 · via Electron

基于 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 类, PorosBrowserWindowBrowserWindow 子类

// 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;

API

import { something } from 'poros';

Main Process

参数 类型 说明
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 是否为生产环境

Renderer Process

透传 umi 的所有属性, 也加入了一些写的属性

参数 类型 说明
logger Logger 日志模块
localStore LocalStore 本地化存储,可以本地文件的方式存储一些配置信息

PorosBrowserWindow

继承至 BrowserWindow

参数 类型 说明
single static readonly boolean 是否单例, 默认:true
URL static readonly string 加载页面地址
OPTIONS static readonly PorosBrowserWindowOptions 窗口配置项
registerWindowEvent () => void 注册窗口事件

PorosWindowManager

管理 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 获取窗口

Logger

配置项 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 的设置不会生效,

LocalStore

保存用户设置、应用程序状态、缓存等

配置项 config/config.ts

export default defineConfig({
   localStore: {
     schema: {
       unicorn: {
          type: 'string',
         default: '🦄',
       },
     },
   },
});

具体配置和用法可参照electron-store

LocalShortcut

将键盘快捷键本地添加到 BrowserWindow 实例,而不使用菜单

PorosBrowserWindow 中内置了打开 DevTools 快捷键 Cmd+Option+IF12

具体用法可参照electron-localshortcut

插件

您也可以直接使用 Umi 插件。如果您遇到任何问题,请联系我。

locale

与 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 语法糖

ipc

简化主进程与渲染进程之间的通信

主进程 API

参数 类型 说明
IpcHandle - ipc 方法注解,PorosBrowserWindow内使用
rendererInvoker {[method: string]: (...args:any[], opts?: { broadcast?: boolean, window?: PorosBrowserWindow})} 渲染进程方法调用器

rendererInvokerbroadcasttrue 时,会给所有窗口广播事件(广播事件无返回值),所有监听了事件的窗口都会收到消息,反之只有相应的窗口下页面会收到消息。PorosBrowserWindow 类中调用,window 默认值为当前窗口,非PorosBrowserWindow 类中必需指定 window 值。

渲染进程 API

参数 类型 说明
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 });

预设插件

  • initial-state
  • access
  • model
  • react-query
  • antd
  • locale
  • ipc

DEMO 预览图

demo

来个 Star🙏🙏🙏

https://github.com/porosjs/poros