quasar electron mode如何打包无边框桌面应用程序
预览
开源项目Tokei Kun
一款简洁的周年纪念app,现已发布APK(安卓)和 EXE(Windows)
项目仓库地址:Github Repo
应用下载链接:Github Releases
Preparation for Electron
quasar dev -m electron# passing extra parameters and/or options to
# underlying "electron" executable:
quasar dev -m electron -- --no-sandbox --disable-setuid-sandbox
# when on Windows and using Powershell:
quasar dev -m electron '--' --no-sandbox --disable-setuid-sandbox
基本命令
quasar dev -m electron
指定以 Electron 模式运行启动 Quasar 开发服务器
传递参数
Linux/MacOS 语法:
quasar dev -m electron -- --no-sandbox --disable-setuid-sandbox
--
: 这个符号表示后面的参数是传递给底层 Electron 可执行文件的,而不是 Quasar CLI
Windows PowerShell 语法:
quasar dev -m electron '--' --no-sandbox --disable-setuid-sandbox
- 在 PowerShell 中需要用引号包裹
--
参数解释
–no-sandbox
禁用 Chromium 的沙盒(sandbox)安全机制沙盒是一种安全功能,限制应用程序对系统资源的访问禁用沙盒可能会降低安全性,但在某些环境下是必要的
–disable-setuid-sandbox
禁用 setuid 沙盒setuid 是一种 Unix 权限机制,允许程序以更高权限运行,在某些 Linux 系统上,如果无法使用 setuid 沙盒,需要禁用此功能
Frameless Electron Window
安装依赖
npm install --save @electron/remote
修改electron-main.js
import { app, BrowserWindow, nativeTheme } from 'electron'
import { initialize, enable } from '@electron/remote/main' // <-- add this
import path from 'path'initialize() // <-- add this// ...mainWindow = new BrowserWindow({width: 1000,height: 600,useContentSize: true,frame: false // <-- add thiswebPreferences: {sandbox: false // <-- to be able to import @electron/remote in preload script// ...}
})enable(mainWindow.webContents) // <-- add thismainWindow.loadURL(process.env.APP_URL)// ...
[!warning]
官方文档中import { initialize, enable } from ‘@electron/remote/main’
这里我出现了报错
改为import { initialize, enable } from '@electron/remote/main/index.js’正常运行
![[import error.png]]
quasar issue:Electron dev app @electron/remote error · Issue #17971 · quasarframework/quasar
[!success] 成功
接下里我们需要处理窗口拖拽以及最小化、最大化与关闭应用
预加载脚本
由于我们无法直接从渲染线程访问 Electron,需要通过 electron 预加载脚本( src-electron/main-process/electron-preload.js
)提供必要功能。因此我们将其修改为:
//src-electron/main-process/electron-preload
import { contextBridge } from 'electron'
import { BrowserWindow } from '@electron/remote'contextBridge.exposeInMainWorld('myWindowAPI', {minimize () {BrowserWindow.getFocusedWindow().minimize()},toggleMaximize () {const win = BrowserWindow.getFocusedWindow()if (win.isMaximized()) {win.unmaximize()} else {win.maximize()}},close () {BrowserWindow.getFocusedWindow().close()}
})
处理窗口拖拽
当我们使用无边框窗口(仅限无边框!)时,还需要为用户提供在屏幕上移动应用窗口的方式。为此,您可以使用 q-electron-drag
和 q-electron-drag--exception
Quasar CSS 辅助类。
[!TIPS] 提示
也许你可以在layout文件中为某些组件添加类q-electron-drag
试试
该功能允许用户在屏幕上点击、按住并同时拖动鼠标时,拖拽应用程序窗口。
最小化、最大化与关闭应用
在某些vue文件(例如添加在MainLayout.vue中)
Template
<q-space /><q-btn dense flat icon="minimize" @click="minimize" />
<q-btn dense flat icon="crop_square" @click="toggleMaximize" />
<q-btn dense flat icon="close" @click="closeApp" />
[!TIP]
若觉得iconminimize
不太习惯(位于底部),可以使用remove
(竖直居中)
q-space
的作用是将q-btn
挤到右边
选项式
<script>
// We guard the Electron API calls with the optional chaining JS operator,
// but this is only needed if we build same app with other Quasar Modes
// as well (SPA/PWA/Cordova/SSR...)export default {setup () {function minimize () {window.myWindowAPI?.minimize()}function toggleMaximize () {window.myWindowAPI?.toggleMaximize()}function closeApp () {window.myWindowAPI?.close()}return { minimize, toggleMaximize, closeApp }}
}
</script>
组合式
<script setup>
// We guard the Electron API calls with the optional chaining JS operator,
// but this is only needed if we build same app with other Quasar Modes
// as well (SPA/PWA/Cordova/SSR...)function minimize() {if (process.env.MODE === 'electron') {window.myWindowAPI?.minimize()}
}function toggleMaximize() {if (process.env.MODE === 'electron') {window.myWindowAPI?.toggleMaximize()}
}function closeApp() {if (process.env.MODE === 'electron') {window.myWindowAPI?.close()}
}
</script>
Electron的 Unable to load preload script 报错解决方案-CSDN博客
Build
quasar build -m electron -d
附完整代码
electron-main.js
import { app, BrowserWindow, ipcMain } from 'electron'
import { initialize, enable } from '@electron/remote/main/index.js' // <-- add this
import path from 'node:path'
import os from 'node:os'
import { fileURLToPath } from 'node:url'initialize() // <-- add this
// needed in case process is undefined under Linux
const platform = process.platform || os.platform()const currentDir = fileURLToPath(new URL('.', import.meta.url))let mainWindowasync function createWindow () {/*** Initial window options*/mainWindow = new BrowserWindow({icon: path.resolve(currentDir, 'icons/icon.png'), // tray iconwidth: 1200,height: 900,useContentSize: true,frame: false,webPreferences: {sandbox: false, // 开启沙盒则preload脚本被禁用,所以得设为falsecontextIsolation: true,// More info: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/electron-preload-scriptpreload: path.resolve(currentDir,path.join(process.env.QUASAR_ELECTRON_PRELOAD_FOLDER, 'electron-preload' + process.env.QUASAR_ELECTRON_PRELOAD_EXTENSION))}})enable(mainWindow.webContents) // <-- add thisif (process.env.DEV) {await mainWindow.loadURL(process.env.APP_URL)} else {await mainWindow.loadFile('index.html')}if (process.env.DEBUGGING) {// if on DEV or Production with debug enabledmainWindow.webContents.openDevTools()} else {// we're on production; no access to devtools plsmainWindow.webContents.on('devtools-opened', () => {mainWindow.webContents.closeDevTools()})}mainWindow.on('closed', () => {mainWindow = null})
}app.whenReady().then(createWindow)app.on('window-all-closed', () => {if (platform !== 'darwin') {app.quit()}
})app.on('activate', () => {if (mainWindow === null) {createWindow()}
})
electron-preload.js
import { contextBridge } from 'electron'
import { BrowserWindow } from '@electron/remote/'contextBridge.exposeInMainWorld('myWindowAPI', {minimize () {BrowserWindow.getFocusedWindow().minimize()},toggleMaximize () {const win = BrowserWindow.getFocusedWindow()if (win.isMaximized()) {win.unmaximize()} else {win.maximize()}},close () {BrowserWindow.getFocusedWindow().close()}
})
/*** This file is used specifically for security reasons.* Here you can access Nodejs stuff and inject functionality into* the renderer thread (accessible there through the "window" object)** WARNING!* If you import anything from node_modules, then make sure that the package is specified* in package.json > dependencies and NOT in devDependencies** Example (injects window.myAPI.doAThing() into renderer thread):** import { contextBridge } from 'electron'** contextBridge.exposeInMainWorld('myAPI', {* doAThing: () => {}* })** WARNING!* If accessing Node functionality (like importing @electron/remote) then in your* electron-main.js you will need to set the following when you instantiate BrowserWindow:** mainWindow = new BrowserWindow({* // ...* webPreferences: {* // ...* sandbox: false // <-- to be able to import @electron/remote in preload script* }* }*/