使用Electron-vite初始化Electron项目

1,138 阅读4分钟

简介

electron是使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序。通过将 Chromium 和 Node.js 嵌入其二进制文件中,Electron 允许你维护一个 JavaScript 代码库,并创建可在 Windows、macOS 和 Linux 上运行的跨平台应用程序——不需要原生electron开发经验。

image.png

为什么用Electron

  • Electron 是一个框架,使开发者能够将 Web 技术(HTML、JavaScript、CSS)、Node.js 及原生代码相结合,构建适用于 macOS、Windows 和 Linux 的跨平台桌面应用程序。 它基于MIT开源许可证,对商业和个人用途均免费。
  • 多功能性:无论你的应用程序需要什么样的界面,都可以使用 HTML、CSS 和 JavaScript 来实现。
  • 可靠性:从 CPU 到操作系统,现代计算机都经过了优化,可以很好地运行 Web 技术。
  • 互操作性:几乎所有带有显示屏的设备——无论是 ATM 机、车载信息娱乐系统、智能电视、冰箱还是任天堂 Switch——都具备显示 Web 技术的方法。
  • 普遍性:很容易找到具有 Web 技术开发经验的开发者

工作流程

image.png

特点

image.png

使用electron-vite初始化项目

官网: cn-evite.netlify.app/guide/

使用electron-vite初始化项目,可以帮助你快速搭建一个electron-react或electron-vue等项目

npm create @quick-start/electron

image.png 组件库选用的antd,如果用最新的antd版本,node环境要求16+

Electron 的生命周期

  • ready:app初始化完成(createWindow)

  • dom-ready:一个窗口中的文本加载完成,后续可以操作dom了

  • did-finsh-load:导航完成时触发,发生在dom-ready之后

  • window-all-closed:所有窗口都被关闭时触发,如果没有监听这个事件,窗口关闭时应用程序会Electron会默认进行退出操作,如果监听了,就需要我们自己需要将当前应该退出(befor-quit,will-quit,quit)

  • befor-quit:在关闭窗口之前触发(没有监听windo-all-closed时,quit就会被触发)

  • will-quit:在窗口关闭并且应用退出时触发

  • quit:当所有窗口被关闭时触发

  • closed:当窗口关闭时触发,此时应删除窗口引用

Electron API

详情参见:electron文档 image.png

从主进程到渲染进程的异步通信(IPC模块通信)

ipcMain模块 是一个 EventEmitter 的实例。 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息。 从渲染器进程发送的消息将被发送到该模块,也可以从主进程向渲染进程发送消息。

  • invoke会返回一个Promise(electron7.0+)
// 在主进程中main/index.js
const { ipcMain } = require('electron')
// 监听渲染进程发送的 'request-data' 消息
ipcMain.handle('request-data', (event, arg) => {
  console.log('Received request for data:', arg); // Received request for data: aaa
  // 模拟异步操作,例如从文件或数据库中获取数据
    const data = new Promise((resolve) => {
        setTimeout(() => {
          resolve({ message: 'Hello from main process!' });
        }, 1000);
    });
    return data;
});

// preload
import { contextBridge, ipcRenderer } from 'electron'
const invokeRequesData = async() => {
    const data = await ipcRenderer.invoke('request-data', 'aaa');
    return data
}
const api = {
    invokeRequesData
}
// 往全局上挂载对应的方法
if (process.contextIsolated) {
  try {
    contextBridge.exposeInMainWorld('api', api)
  } catch (error) {
    console.error(error)
  }
} else {
  window.api = api
}

// 在渲染进程中
export default () => {
    const hanleRequest = async () => {
        const res = await window.api.invokeRequesData()
        console.log(res) // message: 'Hello from main process!'
    }
    return (
        <Button onClick={hanleRequest}>button</Button>
    )
}

  • send从渲染进程向主进程发布异步消息,无返回值,因为它不等待主进程的响应
// 在主进程中main/index.js
const { ipcMain } = require('electron')
ipcMain.on('watch', (event, params) => {
    console.log('输出', event, params)
})
// preload
import { contextBridge, ipcRenderer } from 'electron'

const sendMain = () => {
    ipcRenderer.send('watch', 'hello world');
}
const api = {
    sendMain,
}
// 往全局上挂载对应的方法
if (process.contextIsolated) {
  try {
    contextBridge.exposeInMainWorld('api', api)
  } catch (error) {
    console.error(error)
  }
} else {
  window.api = api
}
// 在渲染进程中
export default () => {
    const handleSendMain = () => {
         window.api.sendMain()
    }
    return (
        <Button onClick={handleSendMain}>button</Button>
    )
}
  • sendSync返回主进程处理后的结果
// 在主进程中main/index.js
const { ipcMain } = require('electron')
// 监听同步消息
ipcMain.on('synchronous-message', (event, arg) => {
  console.log('Received synchronous message:', arg);
  // 处理逻辑,并返回结果
  event.returnValue = 'Synchronous response from main process';
});

const sendSyncMessage = (arg) => { 
    return ipcRenderer.sendSync('synchronous-message', arg);
}
const api = {
    sendSyncMessage
}
// 往全局上挂载对应的方法
if (process.contextIsolated) {
  try {
    contextBridge.exposeInMainWorld('api', api)
  } catch (error) {
    console.error(error)
  }
} else {
  window.api = api
}
// 在渲染进程中
export default () => {
    const handleSyncSend = () => {
        const res = await window.api.sendSyncMessage()
        console.log(res, 'res');
    }
    return (
        <Button onClick={handleSyncSend}>button</Button>
    )
}

页面间通信(渲染进程与渲染进程间)

  • 通知事件
    • 通过主进程转发
    • ipcRenderer.sendTo
  • 数据共享
    • web技术(localStorage,sessionStorage,indexedDB)
    • 使用remote

经验与技巧

  • 少用remote模块
  • 不要用sync模式
  • 在请求+响应的通信模式下,需要自定义超时限制

打包

electron-builder 和elecron-forge区别

image.png

  • electron-builder

    • 更加专注于打包和发布,提供了丰富的配置选项和自动更新功能。
    • 适合需要高度自定义打包过程的项目。
  • electron-forge

    • 提供了一整套的开发工具链,包括项目初始化、开发调试和打包。
    • 适合新项目和需要快速开发的场景。

我们用electron-vite搭建的项目已经配置好了打包命令,执行对应的命令就可以打包对应系统的应用程序了

image.png