本来 electron-builder是支持在windows下开发,然后一条命令打包到不同平台的,但此命令需要使用远程服务器来完成打包,然后此服务器已经停止很长时间了,而且从官方文档可感知后续不会开启。所以要打linux包必须到linux平台下打包。
本文采用Deepin国产linux操作系统为例进行Electron打包:
1.安装node:
1.1 下载
从nodejs官网到本地后上传到Linux服务器,也可在linux中直接下载。
下载地址是:nodejs.org/en/download…
解压到/usr/local/nodejs文件夹。(可自定义位置)
1.2 建立软链接
通过建立软链接的方式将这个设置为全局,使之在任何位置可执行node命令。
$ sudo ln -s /usr/local/nodejs/bin/node /usr/local/bin
$ sudo ln -s /usr/local/nodejs/bin/npm /usr/local/bin
1.3 修改镜像源
编辑npm config修改镜像源:
npm config edit
弹出配置文档,i编辑,esc退出编辑模式,:wq写入后退出。
electron_mirror=https://npm.taobao.org/mirrors/electron/
electron-builder-binaries_mirror=https://npm.taobao.org/mirrors/electron-builder-binaries/
2.下载 Electron + Vite + Vue3+TS 脚手架项目
自己新建vue+vite+electron+ts项目费时且易错,可直接下载下面的脚手架项目来使用。
GitHub - electron-vite/electron-vite-vue: 🥳 Really simple Electron + Vite + Vue boilerplate.
直接下载electron-vite-vue项目到本地,然后传到linux服务器上,打linux包必须在linux服务器上进行。
当然linux要下载安装vscode。(从应用商城中下载)
3.在linux下打包
在linux下安装了vscode,把我们下载的脚手架项目拷贝到linux下,用vscode打开
原项目package.json缺少homepage和description两项配置,加上这两项,然后加上build命令,修改后如下:
{
"name": "electron-vue-vite",
"version": "2.0.0",
"main": "dist/electron/main/index.js",
"author": "路飞",
"homepage":"http://www.baidu.com",
"description": "一个vue+electron脚手架项目",
"license": "MIT",
"private": true,
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build && electron-builder"
},
"engines": {
"node": ">=14.17.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.3",
"electron": "^19.0.3",
"electron-builder": "^23.0.3",
"typescript": "^4.7.3",
"vite": "^2.9.9",
"vite-plugin-electron": "^0.4.6",
"vite-plugin-resolve": "^2.1.2",
"vue": "^3.2.36",
"vue-tsc": "^0.36.0"
},
"env": {
"VITE_DEV_SERVER_HOST": "127.0.0.1",
"VITE_DEV_SERVER_PORT": 3344
},
"keywords": [
"electron",
"rollup",
"vite",
"vue3",
"vue"
]
}
在终端中初始化依赖项:
npm install
等初始化完成后,执行打包命令:
npm run build
运行日志:
saft@saft-PC:~/Desktop/docment/electronvuets$ npm run build
> electron-vue-vite@2.0.0 build /home/saft/Desktop/docment/electronvuets
> vue-tsc --noEmit && vite build && electron-builder
(node:16208) [DEP0025] DeprecationWarning: sys is deprecated. Use util instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
vite v2.9.12 building for production...
✓ 1 modules transformed.
dist/electron/preload/splash.js 1.48 KiB / gzip: 0.70 KiB
dist/electron/preload/splash.js.map 3.71 KiB
vite v2.9.12 building for production...
✓ 1 modules transformed.
dist/electron/main/index.js 1.37 KiB / gzip: 0.77 KiB
vite v2.9.12 building for production...
✓ 17 modules transformed.
dist/electron.fe1dfbad.png 61.65 KiB
dist/vite.92024911.svg 1.50 KiB
dist/vue.03d6d6da.png 6.69 KiB
dist/index.html 0.60 KiB
dist/style.b05f3b27.css 0.59 KiB / gzip: 0.33 KiB
dist/index.0f17d918.js 52.73 KiB / gzip: 21.28 KiB
• electron-builder version=23.1.0 os=5.10.101-amd64-desktop
• loaded configuration file=/home/saft/Desktop/docment/electronvuets/electron-builder.json5
• writing effective config file=release/2.0.0/builder-effective-config.yaml
• packaging platform=linux arch=x64 electron=19.0.5 appOutDir=release/2.0.0/linux-unpacked
• downloading url=https://npm.taobao.org/mirrors/electron/19.0.5/electron-v19.0.5-linux-x64.zip size=83 MB parts=2
• downloaded url=https://npm.taobao.org/mirrors/electron/19.0.5/electron-v19.0.5-linux-x64.zip duration=7.957s
• building target=deb arch=x64 file=release/2.0.0/electron-vue-vite_2.0.0_amd64.deb
• default Electron icon is used reason=application icon is not set
可以看到,electron-builder会默认取到当前系统框架信息os=5.10.101-amd64-desktop,作为参数,打包对应于本框架的应用程序。
这时候在项目release目录下生成了安装包,我们先试试安装此程序:
安装完成后菜单中会出现electron-vue-vite程序。
再试试免安装程序可否直接运行:
点运行后打开electron程序
扩展1:自定义图标
linux中定义应用程序图标与win中有差异。应用程序默认图标以及左上角图标在 electron-builder.json5 文件中设置:
win系统的在win下添加icon节点,并设置ico格式的图标文件为佳。linux和mac应设置为icns格式大小在256*256以上。(在deepin中使用png测试失败)linux下要执行安装程序后才看得到桌面图标效果。根据electronbuilder要求,linux下icns格式文件需要在文件名中包含尺寸,格式如msg@256x256.icns
/**
* electron-builder.json5 文件
*/
{
"appId": "cn.you.app",
"asar": true,
"directories": {
"output": "release/${version}"
},
"files": [
"dist"
],
"mac": {
"icon": "public/msg@256x256.icns",
"artifactName": "${productName}_${version}.${ext}",
"target": [
"dmg"
]
},
"win": {
"icon": "public/msg.ico",
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
],
"artifactName": "${productName}_${version}.${ext}"
},
"linux": {
"icon": "public/msg@256x256.icns",
"category":"Network",
"target": [
"deb"
]
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": false
}
}
png图片在线转ico工具:PNG转ICO - 在线转换图标文件 (aconvert.com)
扩展2:隐藏系统菜单
只需加一句即可
app.whenReady().then(() => {
……
//隐藏系统默认菜单
Menu.setApplicationMenu(null)
})
扩展3:禁用GPU加速
如果本身没有GPU硬件设备,添加一句设置来禁用gpu加速
app.disableHardwareAcceleration()
扩展4:制作托盘小程序
使用Tray创建托盘小程序,托盘的图标需要与之前的图标设置不同,linux下建议用png格式的图片,windows下用ico更佳。
//获取托盘图标。程序默认图标在electron-builder.json5中设置。
function getTrayIcon() {
if (process.platform == 'darwin') {
//MacOS
return join(__dirname, '../../msg@256x256.png');
}
else if (process.platform == 'linux') {
//linux
return join(__dirname, '../../msg@256x256.png');
}
else // windows
return join(__dirname, '../../msg.ico');
}
app.whenReady().then(() => {
createWindow()
// 创建系统托盘
let iconpath=getTrayIcon()
tray = new Tray(nativeImage.createFromPath(iconpath))
const contextMenu = Menu.buildFromTemplate([
{
label: '显示icon路径',
click () { showNotification('提示',iconpath) }
},
{
label: '显示通知',
click () { showNotification('提示',process.platform) }
}, {
label: '子菜单',
submenu: [
{ label: 'Basic' },
{ label: '显示通知',click(){showNotification('提示','这是一条通知消息!')} }
]
},
{ label: '退出程序',
click(){ app.quit()} }
])
tray.setToolTip('This is my application.')
tray.setContextMenu(contextMenu)
})
扩展5:引入element-plus UI组件
项目中添加element-plus组件库制作精美页面。
npm i --save element-plus
main.ts中增加:
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
createApp(App)
.use(router)
.use(ElementPlus, {locale: zhCn})
.mount('#app')
然后就可以使用element控件了
扩展6:播放声音
windows下直接可以这样写:
播歌曲文件:
const playmp3=async ()=>{
var auto=new Audio("庆祝.mp3");
auto.volume=1;
auto.play();
}
文本转声音:
const Speak=async(m:string)=>{
//文字转声音
var u=new SpeechSynthesisUtterance();
u.text=m
//该lang属性使您能够指定文本的语言。zh、 en-US 等
u.lang='zh';
//该rate属性定义了应该说出文本的速度。这应该是介于0和10之间的浮点值,默认值为1。
u.rate=rate.value/10;
//该volume属性允许您调整语音的音量。应在此处指定介于0和1之间的浮点值。默认值为1。
u.volume=volume.value/100;
speechSynthesis.speak(u)
}
linux播放声音相对复杂,首先解决虚拟机deepin声音环境
Vmware安装deepin没有声音解决办法secret_breathe的博客-CSDN博客deepin没有声音
在Deepin系统中没有声音的解决办法Linux教程云网牛站 (ywnz.com)
经过上面教程打开linux声音环境后,在linux下测试播放歌曲没问题,依然是使用上面的代码(使用Audio类来播放),但是播放TTS语音合成就无法播放。
使用以下在线测试工具,在win下打开,不管是Edge还是Chrome浏览器打开,Voice下拉有语言库列表,但在linux下用Chrome打开无Voice列表,造成无法播放声音。
Web Speech Synthesis Demo (eeejay.github.io)
在liunx下的TTS技术先后尝试了以下方案:
Artyom:基于window.speechSynthesis,在linux下依然因为chrome71版本之后的限制播放不了声音。
say.js:基于festival,不支持中文
ekho:中文效果不佳(须安装ekho-7.5.tar.xz版本才能编译成功Ekho 安装_)官网中可直接体验效果。
ekho '有10条新报警消息,请注意查收!'
espeak:中文效果不佳,可使用以下命令播放中文,但发现是外国人讲中国话,极其不自然。10会读成一零。
espeak -v zh 有10条新报警消息,请注意查收!
以下是使用Gespeaker程序,底层调用espeak-ng播放语音的界面:
sudo apt install gespeaker
festival:不支持中文
WebSpeech:在线版本2000元/年,本地版本底层调用的是espeak,中文效果不佳。
扩展7:使用vue-router
使用vue-router进行路由配置
引入vue-router
npm i --save vue-router
创建router/index.ts
import { createRouter, createWebHashHistory } from "vue-router";
const routes= [
{
path: '/login',
name: 'login',
component: () => import('../view/login/index.vue')
},
{
path: '/error',
name: 'error',
component:() => import('../view/error/index.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes: routes
})
export default router
main.ts中增加:
import router from './router'
createApp(App)
.use(router)
扩展8:隐藏标题栏+任意拖动+最大最小关闭按钮事件
将BrowserWindow的frame属性设置为false,就可以实现无标题
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600, frame: false })
win.show()
可拖拽区域设置,将html某一块,添加webkit-app-region:drag属性即可。但这样会遮住按钮等的点击事件,可以在对于控件style里增加 -webkit-app-region: no-drag
<body style="-webkit-app-region: drag">
</body>
最大化、最下话、关闭按钮,需要使用到进程间通信,即渲染进程和窗体进程通讯
在electron的main.js中添加监听
const {app, BrowserWindow, ipcMain} = require('electron')
ipcMain.on('window-max', () => {
if(mainWindow.isMaximized()) {
mainWindow.restore()
}else{
mainWindow.maximize()
}
}
ipcMain.on('window-min', function () {
mainWindow.minimize();
})
ipcMain.on('window-close', function () {
mainWindow.close();
})
在preload.js中添加
contextBridge.exposeInMainWorld('ipcRenderer', {
...ipcRenderer,
on: (channel: any, callback: any) => {
ipcRenderer.on(channel, callback)
}
})
在页面中对按钮添加事件:
<img src="../../assets/min.png" @click="min()" />
<img src="../../assets/close.png" @click="close()" />
……
<script lang="ts" setup>
const min=()=>{
window.ipcRenderer.send("window-min")
}
const close=()=>{
window.ipcRenderer.send("window-close")
}
……
扩展9:自定义标题
定义窗口标题有两个办法:
办法一:直接在内容html中使用title设置标题
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<title>标题就在这里设置</title>
</head>
<body style="margin:0;">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
这种方法适合单页面应用。以上就是vue单页面应用的index.html典型写法。
办法二:使用BrowserWindow的构造参数设置title,但要去掉html中的title,因为html中title优先级更高。
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
title:'这里设置标题',
webPreferences:{
// 渲染进程(rendee.js)中可以使用 nodejs
nodeIntegration: true,
contextIsolation:false,
enableRemoteModule: true, // 启用remote模块
},
});
官方对此参数的说明:titlestring(可选) - 默认窗口标题 默认为"Electron"。 如果由loadURL()加载的HTML文件中含有标签<title>,此属性将被忽略。