当前位置: 首页 > article >正文

学习记录:DAY32

Electron 开发之旅:从入门到实践

前言


接续上一篇 blog,这篇的内容主要和 Electron 有关。
课设不是特别想做下去了,实际核心代码大概只有 3,4 百行左右,比较水……
或许会把 Docker 的部署也做一做(权当是练习了)。

日程


现在是晚上 7 点 40 分,希望 9 点之前能把应用打包好,这样今天还能匀点时间用来复习。
困困困困困困困困困困困困困困困困困困
Electron 的水比我想象的深,搞不懂所以用 bat 了
过 0 点了,都不睡觉是吧,我和你们爆了😡😭😡😭

学习内容


《省流》

  1. Electron 安装与入门
  2. 预加载脚本与进程通信
  3. 打包应用
  4. bat 脚本启动前后端

1. Electron 安装与入门

先放个官方的安装教程:安装指导 | Electron
基本上参照官方的教程安装即可。因为 Electron 的安装过程分为两部分:

  • 下载 npm 包 (镜像)
  • 下载 Electron 二进制文件(GitHub 下载)

所以国服玩家最好设置一下国内的镜像源:

# 设置淘宝镜像源
npm config set registry https://registry.npmmirror.com# 从国内镜像下载二进制包
npm install electron --save-dev --electron-mirror=https://npmmirror.com/mirrors/electron/

接着是入门程序:
官方 api 文档:app | Electron

// main.js
const { app, BrowserWindow } = require('electron')
function createWindow() {const win = new BrowserWindow({ // 创建窗口对象width: 800,height: 600,autoHideMenuBar: true, // 隐藏菜单栏})win.loadURL('https://www.github.com') // 加载网页
}
app.on('ready', () => { // 启动钩子createWindow()
})

如果要启动本地的网页资源:

win.loadFile('./pages/index.html')

通常还需要设置内容安全策略来控制资源的访问:

<!-- index.html -->
<metahttp-equiv="X-Content-Security-Policy"content="default-src 'self'; script-src 'self'"
/>

关于 CSP 的详细说明请参考:内容安全策略(CSP) - HTTP | MDN

窗口默认行为:

// windows 习惯:关闭所有窗口后退出程序
app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
// Mac 习惯
app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

配置自动重启:
这个能保证在编写代码后 electron 应用能自动更新

# 安装 nodemon
npm i nodemon -D# 配置 nodemon.json
{"ignore": ["node_modules","dist"],"restartable": "r","watch": ["*.*"],"ext": "html,js,css","delay": 10000
}# 配置 package.json
"start": "nodemon --exec electron .",

2. 预加载脚本与进程通信

首先要了解 Electron 的流程模型:
由一个入口 主进程(main.js)和多个渲染进程(render.js [即 index.html] 的 js 脚本)组成

预加载脚本(preload.js),作为沟通两者的桥梁

// preload.js
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', { // 形成全局上下文键值对version: process.version,
})

在 main.js 中声明

const path = require('path')
function createWindow() {const win = new BrowserWindow({ ...webPreferences: {preload: path.resolve(__dirname, "./preload.js")}})
}

在 render.js 中调用

const btn1 = document.getElementById('btn1')
btn1.onclick = () => {alert(myAPI.version)
}

进程通信(IPC)是 Electron 中的一个重要概念,实现进程之间的通信
1)单向通信
在 main.js 中导入 ipc 模块:

const { ipcMain } = require('electron')
function createWindow() {.....ipcMain.on('file-save', writeFile)
}
function writeFile(_, data) {fs.writeFileSync(path.join(__dirname, 'output.txt'),data)
}

在 preload.js 中设置信道方法:

const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {version: process.version,saveFile: (data) => {ipcRenderer.send('file-save', data)}
})

在 render.js 中触发方法,将信息 单向 向主进程通信

btn2.onclick = () => {myAPI.saveFile(input.value)
}

2)双向通信
实现原理和单向类似,只是方法细节上有所区别

// main.js
ipcMain.handle('file-read', readFile)
....
function readFile() {return fs.readFileSync(path.join(__dirname, 'output.txt')).toString()
}// preload.js
readFile: () => {return ipcRenderer.invoke('file-read')
}// render.js
btn3.onclick = async () => {let data = await myAPI.readFile()alert(data)
}

!需要注意一个 axios 上的细节:
Electron 的进程间通信是异步的
invoke() 设计就是返回 Promise 来处理这种异步性
Promise 链延续:

  • 如果不 return,Promise 链会在 preload 层中断
  • 加了 return 才能让 Promise 链延续到渲染进程

实际调用示例对比
能正常工作的版本:

// preload.js
contextBridge.exposeInMainWorld('myAPI', {readFile: () => {return ipcRenderer.invoke('file-read') // 有 return}
})
// 渲染进程
const data = await myAPI.readFile() // 能获取到数据

不能工作的版本:

// preload.js
contextBridge.exposeInMainWorld('myAPI', {readFile: () => {ipcRenderer.invoke('file-read') // 无 return}
})
// 渲染进程
const data = await myAPI.readFile() // data 将是 undefined

建议:永远 return IPC 调用的结果:无论是 invoke() 还是 send() 的响应

3. 打包应用

这里用到的打包方法是 electron-builder,配置麻烦,但是自由度比较高

# 安装 electron-builder
npm install electron-builder -D

完整 package.json

"build": {// 应用程序的唯一标识符(反向域名格式)"appId": "com.kacat.testapp",// Windows 平台特定配置"win": {// 应用程序图标的路径(建议使用 256x256 像素的.ico文件)"icon": "./logo.ico",// 构建目标配置"target": [{// 使用 NSIS 制作安装程序(.exe)"target": "nsis",// 目标架构(仅 x64 位)"arch": ["x64"]}]},// NSIS 安装程序配置"nsis": {// 是否一键安装(false 表示显示安装向导)"oneClick": false,// 是否为所有用户安装"perMachine": true,// 是否允许用户更改安装目录"allowToChangeInstallationDirectory": true},// Electron 下载镜像配置(使用国内淘宝镜像加速下载)"electronDownload": {"mirror": "https://npmmirror.com/mirrors/electron/"}
}
# 执行打包
npm run build

4. bat 脚本启动前后端

@echo off
chcp 65001 > nul
title kat-watermarkingset JAR_PATH=kat-watermarking.jar
set NGINX_PATH=nginx
set NGINX_EXEC=nginx.exe
set NGINX_URL=http://localhost:10086
set JDK_DIR=jdk-17.0.2
set JAVA_CMD="%JDK_DIR%\bin\java"
if errorlevel 1 (echo 错误: bat 配置有误,请检查pauseexit /b 1
)echo 正在启动 Java 应用程序...
start "JavaApp" /min cmd /c "%JAVA_CMD% -jar %JAR_PATH% && pause"
if errorlevel 1 (echo 错误: 启动 Java 应用程序失败pauseexit /b 1
)echo 正在启动 Nginx 服务器...tasklist /fi "imagename eq nginx.exe" | find /i "nginx.exe" > nul
if not errorlevel 1 (echo 检测到已有 Nginx 正在运行,正在终止旧进程...taskkill /f /im nginx.exe > nul 2>&1timeout /t 1 /nobreak > nul
)cd "%NGINX_PATH%"
start "" "%NGINX_EXEC%"
if errorlevel 1 (echo 错误: 启动 Nginx 服务器失败pauseexit /b 1
)
cd ..timeout /t 2 /nobreak > nul echo 正在打开 Nginx 网页...
start "" "%NGINX_URL%"
if errorlevel 1 (echo 警告: 无法打开浏览器,请手动访问 %NGINX_URL%
)echo 所有服务已启动完成!
pausetaskkill /f /im nginx.exe > nul 2>&1exit /b 0

其实没有什么技术含量,挑一下有用的讲讲吧:

  • @echo off 关闭命令本身的回显,只显示输出结果(即 echo 指明的字段)
  • chcp 65001 设置控制台字符集为 utf-8
  • > nul 重定向输出到 null(即不显示输出)
  • if errorlevel 1 () 检查上一个命令的退出代码, >=1 为执行错误
  • tasklist /fi "字段 运算符 值" 列出进程列表并条件过滤
  • | 管道符,用于将一个命令的输出传递给另一个命令作为输入
  • find /i "字符串" 查找字符串,不区分大小写
  • taskkill /f /im nginx.exe /f 强制终止 /im 按进程名称终止
  • timeout /t 1 /nobreak 暂停脚本执行 1 秒钟 /nobreak 禁止用户按键跳过等待

结语


事实证明困距离不得不睡觉有很长一段距离。
如果能习惯这个感觉还能正常工作,🤤

相关文章:

学习记录:DAY32

Electron 开发之旅&#xff1a;从入门到实践 前言 接续上一篇 blog&#xff0c;这篇的内容主要和 Electron 有关。 课设不是特别想做下去了&#xff0c;实际核心代码大概只有 3&#xff0c;4 百行左右&#xff0c;比较水…… 或许会把 Docker 的部署也做一做&#xff08;权当是…...

next,react封装axios,http请求

import axios from axios;//声明一个基础接口变量1 let base_url; //配置开发环境 if (process.env.NODE_ENV development) {base_url "http://127.0.0.1/"; } // 配置生产环境 if (process.env.NODE_ENV production) {base_url "http://127.0.0.1/"; …...

元图CAD:一键解锁PDF转CAD,OCR技术赋能高效转换

在建筑、工程与制造领域&#xff0c;图纸的精准性与高效协作是项目成功的关键。然而&#xff0c;传统PDF文件中的文字和图形往往难以直接编辑&#xff0c;手动输入不仅耗时易错&#xff0c;还可能因格式问题导致信息丢失。元图CAD凭借创新的OCR文字识别技术&#xff0c;重新定义…...

Android 平台RTSP/RTMP播放器SDK接入说明

一、技术背景 自2015年起&#xff0c;大牛直播SDK持续深耕音视频直播领域&#xff0c;自主研发并迭代推出跨平台 RTSP/RTMP 播放模块&#xff0c;具备如下核心优势&#xff1a; 全平台兼容&#xff1a;支持 Android/iOS/Windows/Linux 等主流系统&#xff1b; 超低延迟&#…...

Nodejs工程化实践:构建高性能前后端交互系统

一、工程架构设计 1.1 现代化项目初始化 采用多包管理架构&#xff1a; mkdir content-platform && cd content-platform npm init -y npx lerna init mkdir -p {packages/client,packages/server,packages/shared} 关键模块划分&#xff1a; client/: 基于Next.js…...

STM32什么是寄存器

提示&#xff1a;文章 文章目录 前言一、背景二、2.12.2 三、3.1 总结 前言 前期疑问&#xff1a; 1、什么是寄存器&#xff1f; 答&#xff1a;在4GB的地址空间中&#xff0c;512MB的block2上&#xff0c;每4个字节组成32位&#xff0c;这个32位为一个单元&#xff0c;控制&a…...

Linux 的 find 命令使用指南

精通 Linux 的 find 命令:终极使用指南 在 Linux 系统中,find 命令是文件搜索的瑞士军刀,它能基于多种条件在目录树中精准定位文件。无论你是系统管理员还是开发者,掌握 find 都能极大提升工作效率。本文将深入解析 find 的核心用法,并附赠实用示例! 一、基础语法结构 …...

第六个微信小程序:教师工具集

源于工作需要&#xff0c;下面开始。 安装及使用 | Taro 文档 vscode 代码管理 git 辅助 开发技术如上&#xff1a; 1.开始创建模板 taro4.1.1 $ taro init teachers-tools 2.用vsocde开始吧。 选择 第二个文件夹找一。 (base) PS D:\react\teachers-tools> pnpm…...

记录一个用了很久的git提交到github和gitee比较方便的方法

在当前git init后&#xff0c;在隐藏的git文件夹中找到config文件 [user]name thels [remote "github"]url your github repository urlfetch refs/heads/*:refs/remotes/origin/* [remote "gitee"]url your gitee repository urlfetch refs/heads/*:…...

Qt Qml模块功能及功能解析

QtQml 是 Qt 6.0 中用于声明式 UI 开发和应用程序逻辑的核心模块&#xff0c;它提供了 QML 语言的支持和运行时环境。 一、主要功能 1. QML 语言支持 QML 语法解析&#xff1a;支持 QML (Qt Meta-Object Language 或 Qt Modeling Language) 的完整语法 JavaScript 集成&…...

前端八股之JS的原型链

1.原型的定义 每一个对象从被创建开始就和另一个对象关联&#xff0c;从另一个对象上继承其属性&#xff0c;这个另一个对象就是 原型。 当访问一个对象的属性时&#xff0c;先在对象的本身找&#xff0c;找不到就去对象的原型上找&#xff0c;如果还是找不到&#xff0c;就去…...

NLP学习路线图(二十九):BERT及其变体

在自然语言处理(NLP)领域,一场静默的革命始于2017年。当谷歌研究者发表《Attention is All You Need》时,很少有人预料到其中提出的Transformer架构会彻底颠覆NLP的发展轨迹,更催生了以GPT系列为代表的语言模型风暴,重新定义了人类与机器的交互方式。 一、传统NLP的瓶颈:…...

机器翻译模型笔记

机器翻译学习笔记&#xff08;简体中文&#xff09; 1. 任务概述 目标&#xff1a;将英文句子翻译成简体中文。 示例&#xff1a; 输入&#xff1a;Tom is a student. 输出&#xff1a;汤姆是一个学生。 框架&#xff1a;Seq2Seq&#xff08;序列到序列&#xff09;模型。…...

Ref vs. Reactive:Vue 3 响应式变量的最佳选择指南

Ref vs. Reactive&#xff1a;Vue 3 响应式变量的最佳选择指南 在 Vue 3 的 Composition API 中&#xff0c;ref 和 reactive 是创建响应式数据的两种主要方式。许多开发者经常困惑于何时使用哪种方式。本文将深入对比两者的差异&#xff0c;帮助您做出最佳选择。 核心概念解…...

让视觉基础模型(VFMs)像大语言模型(LLMs)一样“会思考”​

视觉检测器的演进&#xff1a;从 DETR 到 Grounding-DINO DINO-R1 的基础是 Grounding-DINO&#xff0c;而 Grounding-DINO 本身是一系列视觉检测器演进的结果。理解这个发展过程对掌握 DINO-R1 的核心技术至关重要。 DETR&#xff1a;用 Transformer 革新目标检测 在 DETR&…...

现代前端框架的发展与演进

现代前端框架的发展与演进是一个非常值得关注的话题&#xff0c;反映了整个前端生态系统的不断演化与技术深度的提升。以下是这一趋势的详细解析&#xff1a; &#x1f4c8; 现代前端框架的发展与演进 &#x1f539; 第一阶段&#xff1a;jQuery 时代&#xff08;2006-2013&am…...

【LLM-Agent】智能体的记忆缓存设计

note 实践&#xff1a;https://modelscope-agent.readthedocs.io/zh-cn/latest/modules/memory.html 文章目录 note一、Agent的记忆实现二、相关综述三、记忆体的构建四、cursor的记忆设计1. 记忆生成提示词2. 记忆评估提示词 五、记忆相关的MCPReference 一、Agent的记忆实现…...

一起学Spring AI:核心概念

人工智能概念 本节描述了 Spring AI 使用的核心概念。我们建议您仔细阅读&#xff0c;以理解 Spring AI 实现背后的思想。 模型&#xff08;Models&#xff09; 人工智能模型是设计用来处理和生成信息的算法&#xff0c;通常模仿人类的认知功能。通过从大型数据集中学习模式…...

Oracle业务用户的存储过程个数及行数统计

Oracle业务用户的存储过程个数及行数统计 统计所有业务用户存储过程的个数独立定义的存储过程定义在包里的存储过程统计所有业务用户存储过程的总行数独立定义的存储过程定义在包里的存储过程📖 对存储过程进行统计主要用到以下三个系统视图: dba_objects:记录了所有独立创…...

PicSharp(图片压缩工具) v1.1.6

PicSharp 一个简单、高效、灵活的跨平台桌面图像压缩应用程序。软件基于Rust实现&#xff0c;高性能低资源&#xff0c;能快速扫描文件或目录&#xff0c;批处理图像。软件还具备组合压缩策略&#xff0c;TinyPNG提供最佳压缩比&#xff0c;但需要互联网连接&#xff0c;对大量…...

前端文件下载常用方式详解

在前端开发中&#xff0c;实现文件下载是常见的需求。根据不同的场景&#xff0c;我们可以选择不同的方法来实现文件流的下载。本文介绍三种常用的文件下载方式&#xff1a; 使用 axios 发送 JSON 请求下载文件流使用 axios 发送 FormData 请求下载文件流使用原生 form 表单提…...

【DAY42】Grad-CAM与Hook函数

内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点: 回调函数lambda函数hook函数的模块钩子和张量钩子Grad-CAM的示例 作业&#xff1a;理解下今天的代码即可 在深度学习中&#xff0c;我们经常需要查看或修改模型中间层的输出或梯度。然而&#xff0c;标准的前向传播和反…...

如何生成和制作PDF文件

在数字化办公的今天&#xff0c;PDF文件已经成为我们工作和学习中不可或缺的一部分。无论是合同、报告、简历&#xff0c;还是电子书、表单&#xff0c;PDF格式都以其跨平台兼容性、不可编辑性和清晰的排版而被广泛使用。但你是否知道&#xff0c;生成和制作PDF文件其实并不复杂…...

【K8S系列】Kubernetes 中 Pod(Java服务)启动缓慢的深度分析与解决方案

本文针对 Kubernetes 中 Java 服务启动时间慢的深度分析与解决方案文章,结合了底层原理、常见原因及具体优化策略: Kubernetes 中 Java 服务启动缓慢的深度分析与高效解决方案 在 Kubernetes 上部署 Java 应用时,启动时间过长是常见痛点,尤其在需要快速扩缩容或滚动更新的…...

【Java学习笔记】StringBuilder类(重点)

StringBuilder&#xff08;重点&#xff09; 1. 基本介绍 是一个可变的字符串序列。该类提供一个与 StringBuffer 兼容的 API&#xff0c;但不保证同步&#xff08;StringBuilder 不是线程安全的&#xff09; 该类被设计用作 StringBuffer 的一个简易替换&#xff0c;用在字符…...

JavaScript ES6 解构:优雅提取数据的艺术

JavaScript ES6 解构&#xff1a;优雅提取数据的艺术 在 JavaScript 的世界中&#xff0c;ES6&#xff08;ECMAScript 2015&#xff09;的推出为开发者带来了许多革命性的特性&#xff0c;其中“解构赋值”&#xff08;Destructuring Assignment&#xff09;无疑是最受欢迎的功…...

iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出

在vue项目中使用iview 框架部分组件时&#xff0c;直接引入使用报Maximum call stack size exceeded image.png 堆栈溢出 解决方案 更换组件名称就可以了 image.png 或 image.png 就可以了 猜测是因为和vue自己提供的组件名称一致了&#xff0c;重名问题导致的&#xff0c;具体…...

基于Halcon深度学习之分类

***** ***环境准备*** ***系统&#xff1a;win7以上系统 ***显卡&#xff1a;算力3.0以上 ***显卡驱动&#xff1a;10.1以上版本&#xff08;nvidia-smi查看指令&#xff09;***读取深度学习模型*** read_dl_model (pretrained_dl_classifier_compact.hdl, DLModelHandle) ***获…...

零基础在实践中学习网络安全-皮卡丘靶场(第十五期-URL重定向模块)

本期内容和之前的CSRF&#xff0c;File inclusion有联系&#xff0c;复习后可以更好了解 介绍 不安全的url跳转 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目…...

技巧小结:根据寄存器手册写常用外设的驱动程序

需求&#xff1a;根据STM32F103寄存器手册写DMA模块的驱动程序 一、分析标准库函数的写法&#xff1a; 各个外设的寄存器地址定义在stm32f10x.h文件中&#xff1a;此文件由芯片厂家提供;内核的有关定义则定义在core_cm3.h文件中&#xff1a;ARM提供; 1、查看外设区域多级划分…...