vue vite ts electron ipc arm64

初始化

npm init vue # 全选 yes
npm i # 进入项目目录后使用
npm install electron electron-builder -D
npm install commander -D # 额外组件

增加文件

新建 plugins 文件夹

src/background.ts

属于主进程

ipcMain.on、ipcMain.handle 都用于主进程监听 ipc,ipcMain.on 用于监听 ipcRenderer.send,ipcMain.handle 用于监听 ipcRenderer.invoke 并 return xxx

ipc 单向:
从渲染进程发向主进程:ipcRenderer.send
从主进程发向渲染进程:window.webContents.send

ipc 双向:
从渲染进程发向主进程,主进程还会返回发向渲染进程:ipcRenderer.invoke
从主进程发向渲染进程,渲染进程还会返回发向主进程:没有类似于 ipcRenderer.invoke 的,需要间接实现。主进程使用 window.webContents.send,渲染进程使用 ipcRenderer.send

import { app, BrowserWindow, screen, ipcMain } from 'electron'
import path from 'path'
import { Command } from 'commander';app.whenReady().then(() => {const command = new Commandlet width, heightlet optionscommand.option('-m, --maximize', 'maximize window').option('-l, --location <>', 'location of load index page', 'index.html').option('-d, --dev', 'openDevTools').option('--no-sandbox', 'other').parse()options = command.opts()if (options.maximize) {width = screen.getPrimaryDisplay().workAreaSize.widthheight = screen.getPrimaryDisplay().workAreaSize.height}else {width = 800height = 600}const window = new BrowserWindow({width: width,height: height,autoHideMenuBar: true,webPreferences: {preload: path.join(__dirname, 'preload.js')}})if (options.location.indexOf(':') >= 0)window.loadURL(options.location)elsewindow.loadFile(options.location)if (options.dev)window.webContents.openDevTools()ipcMain.on('rtm', () => {console.log('rtm')window.webContents.send('mtr')})ipcMain.on('rtm_p', (e, p) => {console.log(p)window.webContents.send('mtr_p', `mtr_p ${p}`)})ipcMain.handle('rtmmtr_p', (e, p) => {console.log(p)return 'rtmmtr_p_return'})
})

src/preload.ts

预加载脚本,用来给渲染进程提供使用 ipcRenderer 的方法
rtm 是渲染进程发向主进程;rtmmtr 是从渲染进程发向主进程,主进程还会返回发向渲染进程;mtr 是主进程发向渲染进程

import { contextBridge, ipcRenderer } from 'electron'contextBridge.exposeInMainWorld('electronAPI', {rtm: () => ipcRenderer.send('rtm'),rtm_p: (p: any) => ipcRenderer.send('rtm_p', p),rtmmtr_p: (p: any) => ipcRenderer.invoke('rtmmtr_p', p),mtr: (p: any) => ipcRenderer.on('mtr', p),mtr_p: (p: any) => ipcRenderer.on('mtr_p', p),
})

src/renderer.d.ts

给渲染进程用的 preload.ts 里的方法的类型声明

export interface IElectronAPI {rtm: () => Promise<any>,rtm_p: (p: any) => Promise<any>,rtmmtr_p: (p: any) => Promise<any>,mtr: (p: any) => Promise<any>,mtr_p: (p: any) => Promise<any>,
}declare global {interface Window {electronAPI: IElectronAPI}
}

plugins/vite.electron.dev.ts

自定义 dev 方法,用于启动 vite 后带起 electron

// 导入需要使用的类型和库
import type { Plugin } from 'vite'
import type { AddressInfo } from 'net'
import { spawn } from 'child_process'
import fs from 'fs'// 导出Vite插件函数
export const viteElectronDev = (): Plugin => {return {name: 'vite-electron-dev',// 在configureServer中实现插件的逻辑configureServer(server) {// 定义初始化Electron的函数const initElectron = () => {// 使用esbuild编译TypeScript代码为JavaScriptrequire('esbuild').buildSync({entryPoints: ['src/background.ts', 'src/preload.ts'],bundle: true,outdir: 'dist',platform: 'node',external: ['electron']})}// electron 运行let electron_run = (ip: string) => {initElectron()// 启动Electron进程let electronProcess = spawn(require('electron'), ['dist/background.js', '-l', ip, '-d'])// 监听Electron进程的stdout输出electronProcess.stdout?.on('data', (data) => {console.log(`${data}`);});return electronProcess}// 监听Vite的HTTP服务器的listening事件server?.httpServer?.once('listening', () => {// 获取HTTP服务器的监听地址和端口号const address = server?.httpServer?.address() as AddressInfoconst ip = `http://localhost:${address.port}`let electronProcess = electron_run(ip)// 监听主进程代码的更改fs.watch('src', () => {// 杀死当前的Electron进程electronProcess.kill()electronProcess = electron_run(ip)})})}}
}

plugins/vite.electron.build.ts

自定义 build 方法,这里打包了 linux 的 x64、arm64 的包

import type { Plugin } from 'vite'
import * as electronBuilder from 'electron-builder'
import path from 'path'
import fs from 'fs'// 导出Vite插件函数
export const viteElectronBuild = (): Plugin => {return {name: 'vite-electron-build',// closeBundle是Vite的一个插件钩子函数,用于在Vite构建完成后执行一些自定义逻辑。closeBundle() {// 定义初始化Electron的函数const initElectron = () => {// 使用esbuild编译TypeScript代码为JavaScriptrequire('esbuild').buildSync({entryPoints: ['src/background.ts', 'src/preload.ts'],bundle: true,outdir: 'dist',platform: 'node',external: ['electron']})}// 调用初始化Electron函数initElectron()// 修改package.json文件的main字段,不然会打包失败const json = JSON.parse(fs.readFileSync('package.json', 'utf-8'))json.main = 'background.js'fs.writeSync(fs.openSync('dist/package.json', 'w'), JSON.stringify(json, null, 2))// 创建一个空的node_modules目录 不然会打包失败fs.mkdirSync(path.join(process.cwd(), "dist/node_modules"));// 使用electron-builder打包Electron应用程序electronBuilder.build({config: {appId: 'com.example.app',productName: 'vite-electron',directories: {output: path.join(process.cwd(), "release"), //输出目录app: path.join(process.cwd(), "dist"), //app目录},linux: {"target": [{"target": "AppImage","arch": ["x64", "arm64"]}]}}})}}
}

修改源文件

src/App.vue

属于渲染进程

window.electronAPI.xxx() 就是预加载脚本(preload.ts)给渲染进程提供的使用 ipcRenderer 的方法
window.electronAPI.mtr 和 …mtr_p (mtr:main to renderer)用于监听主进程发过来的消息
由于 window.electronAPI.rtmmtr_p 使用 ipcRenderer.invoke,这是异步方法,如果不在其前面加 await 而直接获取会得到一个用于异步执行的对象(Promise),其内容包含了需要异步执行的东西,await 就是等待该对象运行结束从而获取正确值,而 await 需要其调用者是异步的,所以 increment() 也加上了 async(异步标志)

<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
import { ref } from 'vue'// 响应式状态
const count = ref(0)// 用来修改状态、触发更新的函数
async function increment() {count.value++window.electronAPI.rtm()window.electronAPI.rtm_p(`rtm_p ${count.value}`)const rtmmtr_p = await window.electronAPI.rtmmtr_p(`rtmmtr_p ${count.value}`)console.log(rtmmtr_p)
}window.electronAPI.mtr(() => {console.log('mtr')
})window.electronAPI.mtr_p((e: any, p: any) => {console.log(p)
})
</script><template><button @click="increment">hhh: {{ count }}</button><header><img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" /><div class="wrapper"><HelloWorld msg="You did it!" /><nav><RouterLink to="/">Home</RouterLink><RouterLink to="/about">About</RouterLink></nav></div></header><RouterView />
</template><style scoped>
header {line-height: 1.5;max-height: 100vh;
}.logo {display: block;margin: 0 auto 2rem;
}nav {width: 100%;font-size: 12px;text-align: center;margin-top: 2rem;
}nav a.router-link-exact-active {color: var(--color-text);
}nav a.router-link-exact-active:hover {background-color: transparent;
}nav a {display: inline-block;padding: 0 1rem;border-left: 1px solid var(--color-border);
}nav a:first-of-type {border: 0;
}@media (min-width: 1024px) {header {display: flex;place-items: center;padding-right: calc(var(--section-gap) / 2);}.logo {margin: 0 2rem 0 0;}header .wrapper {display: flex;place-items: flex-start;flex-wrap: wrap;}nav {text-align: left;margin-left: -1rem;font-size: 1rem;padding: 1rem 0;margin-top: 1rem;}
}
</style>

修改配置文件

tsconfig.node.json

{"extends": "@tsconfig/node18/tsconfig.json","include": ["vite.config.*","vitest.config.*","cypress.config.*","nightwatch.conf.*","playwright.config.*","plugins/**/*.ts"],"compilerOptions": {"composite": true,"module": "ESNext","types": ["node"]}
}

vite.config.ts

import { fileURLToPath, URL } from 'node:url'import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { viteElectronDev } from './plugins/vite.electron.dev'
import { viteElectronBuild } from './plugins/vite.electron.build'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),vueJsx(),viteElectronDev(),viteElectronBuild()],base: './', //默认绝对路径改为相对路径 否则打包白屏resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}}
})

使用

启动:npm run dev
打包:npm run build

npm run dev启动后桌面出现应用界面,并自动打开开发者工具。修改 src 下的任何文件都会自动编译并重启应用
打包后启动可以添加 -m 全屏,-d 打开开发者工具

其他

  • https://xiaoman.blog.csdn.net/article/details/131713875?spm=1001.2014.3001.5502
  • https://www.electronjs.org/zh/docs/latest/tutorial/context-isolation
  • https://www.electronjs.org/zh/docs/latest/tutorial/ipc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nodejs + express 调用本地 python程序

假设已经安装好 nodejs ; cd /js/node_js ; 安装在当前目录的 node_modules/ npm install express --save 或者 cnpm install express --save web 服务器程序 server.js const http require(http); const express require(express); const path require(path); const …

软件外包开发的需求分析

需求分析是软件开发中的关键步骤&#xff0c;其目的是确定用户需要什么样的软件&#xff0c;以及软件应该完成哪些任务。需求分析是软件工程的早期工作&#xff0c;也是软件项目成功的基础&#xff0c;因此花费大量精力和时间去做好需求分析是值得的。今天和大家分享软件需求分…

【开发问题】flink-cdc不用数据库之间的,不同类型的转化

不同的数据库之期间数据类型转化 问题来源与原因解决过程&#xff0c;思路错误&#xff0c;导致各种错误错误思路是什么 正确解决方式&#xff0c;找官网对应的链接器&#xff0c;数据转化 问题来源与原因 我一开始是flink-cdc&#xff0c;oracle2Mysql&#xff0c;sql 我一开…

idea中设置maven本地仓库和自动下载依赖jar包

1.下载maven 地址&#xff1a;maven3.6.3 解压缩在D:\apache-maven-3.6.3-bin\apache-maven-3.6.3\目录下新建文件夹repository打开apache-maven-3.6.3-bin\apache-maven-3.6.3\conf文件中的settings.xml编辑&#xff1a;新增本地仓库路径 <localRepository>D:\apache-…

[元带你学: eMMC协议 29] eMMC 断电通知(PON) | 手机平板电脑断电通知

依JEDEC eMMC及经验辛苦整理,原创保护,禁止转载。 专栏 《元带你学:eMMC协议》 内容摘要 全文 2000 字, 主要内容 前言 断电通知是什么? 断电通知过程

【Kafka】常用操作

1、基本概念 1. 消息&#xff1a; Kafka是一个分布式流处理平台&#xff0c;它通过消息进行数据的传输和存储。消息是Kafka中的基本单元&#xff0c;可以包含任意类型的数据。 2. 生产者&#xff08;Producer&#xff09;&#xff1a; 生产者负责向Kafka主题发送消息。它将消息…

Vue3项目中没有配置 TypeScript 支持,使用 TypeScript 语法

1.安装 TypeScript&#xff1a;首先&#xff0c;需要在项目中安装 TypeScript。在终端中运行以下命令 npm install typescript --save-dev2.创建 TypeScript 文件&#xff1a;在 Vue 3 项目中&#xff0c;可以创建一个以 .ts 后缀的文件&#xff0c;例如 MyComponent.ts。在这…

103、Netty是什么?和Tomcat有什么区别?特点是什么?

Netty是什么&#xff1f;和Tomcat有什么区别&#xff1f;特点是什么&#xff1f; 一、Netty是什么二、Netty和Tomcat有什么区别三、Netty的特点 一、Netty是什么 Netty是一个基于NIO的异步网络通信框架&#xff0c;性能高&#xff0c;封装了原生NIO编码的复杂度&#xff0c;开…

Python web实战 | Docker+Nginx部署python Django Web项目详细步骤【干货】

概要 在这篇文章中&#xff0c;我将介绍如何使用 Docker 和 Nginx 部署 Django Web 项目。一步步讲解如何构建 Docker 镜像、如何编写 Docker Compose 文件和如何配置 Nginx。 1. Docker 构建 Django Web 项目 1.1 配置 Django 项目 在开始之前&#xff0c;我们需要有一个 D…

QT自定义控件实现并导入

QT自定义控件 介绍 QT Creator自定义控件和designer控件导入 1.安装QT5.7.1 2.将QT编译器目录、lib目录、include目录导入path 使用说明 使用说明按照 1.创建QtDesigner自定义控件工程&#xff0c;打开Qt Creator,创建一个Qt 设计师自定义控件&#xff0c;如下图所示&#xf…

CK_03靶机详解

CK_03靶机详解 靶场下载地址&#xff1a;https://download.vulnhub.com/ck/MyFileServer_3.zip 这个靶机开放的端口特别多&#xff0c;所以给我们的误导也很多&#xff0c;我直接按照正确的思路来。 因为开着445所以就枚举了一下靶机上共享的东西&#xff0c;发现两个share的…

c# 创建一个未定义类的临时对象列表

使用场景&#xff1a;要使用的数据太多&#xff0c;列表/字典无法满足需求&#xff0c;需要传入对象&#xff0c;但是又不想创建模型 new[] 是一种用于创建匿名类型数组的写法。它是 C# 中的一种语法糖&#xff0c;用于简化数组的初始化过程。 在下面代码示例中&#xff0c;ne…

elment-ui的侧边栏 开关及窗口联动

<template><div class"asders"><el-aside width"200px"><div class"boxbody"><div>源码外卖</div><el-switch v-model"isCollapse" :active-value"true" :inactive-value"fals…

通过Filebeat进行日志监控

对系统的日志监控&#xff0c;通用做法是使用ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;进行监控和搜索日志&#xff0c;这里给出另一种方案&#xff1a;通过Filebeat接收日志到Kafka&#xff0c;监控平台接收Kafka&#xff0c;并通过WebSocket实时展示。 这…

CAD Voronoi3D V1.0.1 版本更新说明

更新说明 CAD Voronoi3D V1.0.1版本对泰森多边形晶格进行进一步的优化。 采用新算法大幅度减少形体边界出现小晶格的可能性&#xff0c;使区块更均匀&#xff1a; 优化曲边边界晶格曲率问题&#xff0c;消除曲边形体晶格边界曲率过大现象&#xff1a; 优化生成算法&#xff…

Bash编程

目录&#xff1a; bash编程语法bash脚本编写 1.bash编程语法 Bash 编程基础 变量引号数组控制语句函数 Bash 变量 语法&#xff1a; Variable_namevalue Bash 变量定义的规则 变量名区分大小写&#xff0c;a和A为两个不同的变量。变量名可以使用大小写字母混编的形式进行…

iOS - 解压ipa包中的Assert.car文件

项目在 Archive 打包后&#xff0c;生成ipa包 将 xxx.ipa文件修改为zip后缀即 xxx.zip &#xff0c;然后再双击解压&#xff0c;会生成一个 Payload 文件夹&#xff0c;里面一个文件 如下图&#xff1a; 然后显示改文件的包内容&#xff1a; 解压 Assets.car 文件的方式&…

Linux操作系统1-命令篇

不同领域的主流操作系统 桌面操作系统 Windos Mac os Linux服务器操作系统 Unix Linux(免费、稳定、占有率高) Windows Server移动设备操作系统 Android(基于Linux,开源) ios嵌入式操作系统 Linux(机顶盒、路由器、交换机) Linux 特点&#xff1a;免费、开源、多用户、多任务…

Qt小妙招:如何在可执行文件生成后,在pro文件中添加其他命令操作?

问题描述&#xff1a; 场景1&#xff1a;我的可执行文件设置生成路径为某个最终目录的bin目录下&#xff0c;当我要修改某些config.ini或者xxx.json,或者一些qss&#xff0c;css文件的时候&#xff0c;我想直接在构建的时候&#xff0c;Qtcreator帮我直接拷贝过去&#xff0c;…

flutter:BottomNavigationBar和TabBar

区别 BottomNavigationBarr和TabBar都是用于创建导航栏的组件&#xff0c;但它们有一些区别。 位置不同&#xff1a;BottomNavigationBar通常位于屏幕底部&#xff0c;用于主要导航&#xff1b;而TabBar通常位于屏幕顶部或底部&#xff0c;用于切换不同的视图或页面。 样式不…