React+Electron开发桌面应用以及踩的坑
💡 根据 遗忘曲线:如果没有记录和回顾,6天后便会忘记75%的内容,所以特此记录下Electron 踩的坑
Electron 官网
www.electronjs.org/zh/docs/lat…
前言
最近公司 Electron
项目需求,经过对比,还是用比较喜欢的React
+ Electron
的形式开发,网上也有挺多从 0 开始建项目,但亲手实践了之后还是遇到了不少问题,在此记录下,希望能帮到遇到类似问题的银。
线上看的比较好比较详细的一些帖子
步骤
安装 运行
1. 用 create-react-app
创建一个 react
项目
create-react-app "项目名"
我是将 create-react-app
安装到了全局
2. 添加 Electron
包到本地环境
!!!此处我装在了 desktop 文件夹下,详解看第三部
npm i Electron -D
顺带也把 electron-builder
这个包装上,后面打包要用
同时我也装了识别当前是开发环境还是本地环境的 cross-env
版本如下
Node.JS
版本是 v16.20.2
3. 我的目录结构 (此处参考了第一篇文章,觉得这种分离很干净)
将 Electron
相关的都放在了 desktop 文件夹下,并且 Electron
、electron-builder
、cross-env
都装在了这个目录下,后续本地启动和打包都在这个层级下输入命令启动
当然也可以直接放在外层, 外层的package.json
显示,只需要在Electron
入口文件中路径能指过去就 OK
4. main 入口文件 js
// main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// const path = require('path')
const path = require('node:path')
const isDevelopment = process.env.NODE_ENV === 'development'
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
// width: 800,
// height: 600,
width: 1160,
height: 752,
minHeight: 632,
minWidth: 960,
show: true, //布尔值,指定创建窗口后是否立即显示
frame: true, //布尔值,指定是否显示窗口的外部框架(包括标题栏和控制按钮)(无边框)
title: 'WuKong',
icon: path.resolve(__dirname, './assets/windows.png'),
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
if (isDevelopment) {
//本地环境
mainWindow.loadURL('http://localhost:3000/')
} else {
const entryPath = path.resolve(__dirname, '../build/index.html') //这个位置是关键,一定要指到react项目打包后的位置
console.log('entryPath====', entryPath);
mainWindow.loadFile(entryPath)
}
// 用来解决载入闪白屏问题
mainWindow.once('ready-to-show', () => {
mainWindow.show()
})
// 打开开发工具
mainWindow.webContents.openDevTools()
}
// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
// 在 macOS 系统内, 如果没有已开启的应用窗口
// 点击托盘图标时通常会重新创建一个新窗口
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此, 通常
// 对应用程序和它们的菜单栏来说应该时刻保持激活状态,
// 直到用户使用 Cmd + Q 明确退出
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
// 在当前文件中你可以引入所有的主进程代码
// 也可以拆分成几个文件,然后用 require 导入。
这里的 path.resolve
、path.join
都是 Node.js 中的方法,目的是拼接路径,前面的 __dirname
变量是当前位置
5. desktop 目录下的 package.json
文件
{
"name": "desktop",
"productName": "WuKong",
"version": "1.0.0",
"description": "",
"main": "main/index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev-electron": "cross-env NODE_ENV=development electron main/index.js",
"prod-electron": "cross-env NODE_ENV=production electron main/index.js",
"build-electron-win64": "electron-builder -w --x64"
},
"build": {
"productName": "WuKong",
"appId": "wuKong.electron.app",
"files": [
"build/**/*",
"main/**/*"
],
"directories": {
"output": "dist"
},
"nsis": {
"oneClick": false,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"installerIcon": "./main/assets/logo.ico",
"uninstallerIcon": "./main/assets/logo.ico",
"installerHeaderIcon": "./main/assets/logo.png",
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "WuKong"
},
"win": {
"icon": "./main/assets/logo.ico",
"artifactName": "${productName}-${version}-${os}-${arch}.${ext}",
"target": "nsis"
},
"extends": null
},
"author": "",
"license": "ISC",
"devDependencies": {
"cross-env": "^7.0.3",
"electron": "^31.0.2",
"electron-builder": "^24.13.3"
}
}
这个文件夹下一开始没有package.json
,可以 npm init
一下
具体字段大概都什么意思第一篇文章写的很全,可以去照着看
dev-electron
在本地环境运行
prod-electron
再生产环境运行
build-electron-win64
打包
命令不重要,这个自己随便定义,着重看 script 后面执行的内容
其中的 "main": "main/index.js",
要指向上面的 main 文件夹下的 index.js
6. 运行
执行我的本地环境
npm run dev-electron
看 main 下 js 文件中配置的内容
if (isDevelopment) {
//本地环境
mainWindow.loadURL('http://localhost:3000/')
} else {
const entryPath = path.resolve(__dirname, '../build/index.html')
console.log('entryPath====', entryPath);
mainWindow.loadFile(entryPath)
}
输入上面的命令执行的 mainWindow.loadURL('http://localhost:3000/')
,所以此时你得保证,你得本地 3000 端口有服务在运行着,react
本身项目启动时默认端口就是这个,所以要在之前 npm start
启动本身项目
到这里如果配置什么都 OK 的话 应该很轻松就能看到本来 React 项目的内容
我这里简单把原来的 react logo 换了个图标 卍,解!!!
然后测试执行身产环境的命令 npm run prod-electron
执行的是上面 else 内的内容
const entryPath = path.resolve(__dirname, '../build/index.html')
console.log('entryPath====', entryPath);
mainWindow.loadFile(entryPath)
我这里遇到了第一个坑,页面空白,同时后面打包也会白屏这俩是一个问题,就是文件路径指向问题,这块放到后面白屏问题说
ok 假如成功运行看到的是和上面 卍
页面相同的效果,这里右侧开了控制台是配置里面设置的
大家记得上到正式环境时给关掉
打包
这里用到了 electron-builder
这个工具,上面还没装得,装一下
报错 1 - 网络
我这里打包过程中遇到好几个错,首先是提示下载 download ... 这个包 winCodeSign-2.6.0.7z
,这个问题看网上应该是 GitHub
在国内网络不稳,老是下载失败造成的,网上的解决方法是直接把这个包下载下来放到本地 electron
文件内,试了可行。
如果不行我还打算开个梯子试下,没用上,如果各位包放到本地还是报错的话可以试试看
下面说下包下载完后具体放到哪个位置,因为设备问题,我只试了 window 环境下的
通常在这个位置
C:\Users\Mr.Liu\AppData\Local
这两个文件夹下的 Cache
中,一开始我只放在了 builder 中,不好时,两个都放了之后不报那个错了
报错 2 - 图片
如果打包时控制台提示和 图片相关的,比如某某 logo.icon
图片有问题,我这边是因为图意省事,直接在网上下的 .png
格式图片,直接改了后缀名,导致打包时提示非法无法识别,乖乖上网上找了专门的 ico 网站生成的.ico
格式图片就好了
我用的这个网站 如果大家看的时候还能打开可以直接拿去用
www.toolhelper.cn/Image/Image…
打包成功后会在 dist
目录下生成这种文件
其中外层的 x64.exe
是安装包,内部的.exe
是直接可以启动的
报错 3 - 页面空白
这里回到本地启动生成环境那一步,假如这里启动后是白屏并且,控制台报这种错 Failed to load resource: net::ERR_FILE_NOT_FOUND
那么生成环境还有打包后的 window 软件都会这样,本质是没找到指向的index.html
文件
打开打包好的index.html
(此时应该是一行代码),恢复一下代码格式可以看到
这里是原 react 项目设置下打包遵循相对路径就可以了,在外层的 package.json
里面写这个
"homepage": "./",
然后在打包 (打包外层的 react 项目)npm start
再同样的方法看下 index.html
发现已经变过来了,网上有同志手动改这个文件的,貌似也行,但不太优雅
然后将打包好的文件放到内部的 build 文件夹中,因为我的 main 下的 js 路径指向的是内部的 build 文件夹,如果大家直接在外部写的,指向对路径就可以
然后执行打包命令
build-electron-win64
直接看打完包的dist
文件
完事,下班, 卍解!
转载自:https://juejin.cn/post/7384781386832298022