vue3+vite+js項目引入electron構建跨平臺桌面應用

1.準備工作

① 必要安裝node.js、vue、vite、electron、pnpm

? ? ? ? 本人用的node版本v18.17.1、vue版本^3.4.19、vite版本^3.2.7、electron版本^35.1.4

② 開發調試打包安裝

"devDependencies": {"concurrently": "^9.1.2","electron-builder": "^26.0.12", "electron-devtools-installer": "^4.0.0","vite-plugin-electron": "^0.29.0", "vite-plugin-electron-renderer": "^0.14.6",   "wait-on": "^8.0.3"
}

package.json結構:

{"name": "okyi_admin","private": true,"version": "0.0.1","main": "electron/main.js", // 改動點1"scripts": {"dev": "vite","preview": "vite preview","build": "vite build --mode production",// 改動點2 注意此處端口為5173,在vite.config.js中server下的port啟動端口務必保持一致"electron": "wait-on tcp:5173 && electron .","electron:dev": "concurrently -k \"pnpm run dev\" \"pnpm run electron\"","electron:build": "pnpm run build && electron-builder","electron:buildAll": "pnpm run build && electron-builder -wml","postinstall": "electron-builder install-app-deps"},"dependencies": {"@electron/remote": "^2.1.2","@element-plus/icons-vue": "^2.0.9","@types/node": "^18.6.5","@wangeditor/editor": "^5.1.23","@wangeditor/editor-for-vue": "^5.1.12","add": "^2.0.6","animate.css": "^4.1.1","axios": "1.6.0","crypto-js": "^4.2.0","electron-reload": "2.0.0-alpha.1", // 改動點3"element-plus": "2.2.21","js-cookie": "^3.0.1","path-to-regexp": "^6.2.1","pinia": "^2.0.17","pinia-plugin-persist": "^1.0.0","unplugin-element-plus": "^0.4.1","vue": "^3.4.19","vue-router": "^4.1.3","vue3-video-play": "^1.3.2","ws": "^8.14.2","yarn": "^1.22.19"},"devDependencies": {"@vitejs/plugin-vue": "^3.0.0","babel-eslint": "^10.1.0","concurrently": "^9.1.2", // 改動點4"consola": "^2.15.3","electron": "^35.1.4", // 改動點5"electron-builder": "^26.0.12", // 改動點6"electron-devtools-installer": "^4.0.0", // 改動點7"eslint": "^8.25.0","eslint-config-prettier": "^8.5.0","eslint-plugin-html": "^7.1.0","eslint-plugin-prettier": "^4.2.1","eslint-plugin-vue": "^9.6.0","less": "^4.2.0","prettier": "^2.7.1","sass": "^1.55.0","sass-loader": "^13.1.0","unplugin-auto-import": "^0.11.1","unplugin-vue-components": "^0.22.3","vite": "^3.2.7","vite-plugin-electron": "^0.29.0", // 改動點8"vite-plugin-electron-renderer": "^0.14.6", // 改動點9"vite-plugin-style-import": "^2.0.0","wait-on": "^8.0.3" // 改動點10},// 改動點11"build": {"appId": "com.yourcompany.yourapp","productName": "Your App","copyright": "Copyright ? 2025","directories": {"output": "release/${version}", // 打包后產物路徑"buildResources": "build-electron"},"files": ["dist/**/*","electron/**/*","!**/node_modules/**/*"],"win": {"target": "nsis","icon": "public/icon.ico" // 應用logo路徑},"mac": {"target": "dmg","icon": "public/icon.icns", // 應用logo路徑"category": "public.app-category.productivity"},"linux": {"target": "AppImage","icon": "public/icon.png" // 應用logo路徑},"nsis": {"oneClick": false,"allowToChangeInstallationDirectory": true}},
}

2.vite.config.js中修改如下:

import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import * as path from 'path';
... 其它導入 ...import electron from 'vite-plugin-electron'
import electronRenderer from 'vite-plugin-electron-renderer'export default defineConfig((env) => {const evnMap = loadEnv(env.mode, process.cwd());console.log(`當前運行環境配置信息 evnMap = ${JSON.stringify(evnMap)}`);return {base: './', // 必須設置為相對路徑resolve: {alias: {'@': path.resolve(__dirname, 'src'),'@a': path.resolve(__dirname, 'src/assets'),'@u': path.resolve(__dirname, 'src/utils'),'@c': path.resolve(__dirname, 'src/components'),'@api': path.resolve(__dirname, 'src/api'),},},... 其它配置 ...build: {... 其它配置 ...emptyOutDir: false, // 避免electron構建被清空},plugins: [... 其它配置 ...electron({entry: 'electron/main.js',onstart(options) {options.startup(['.', '--no-sandbox']).then(r => {})},vite: {build: {sourcemap: true,outDir: 'dist-electron',},},}),electronRenderer({nodeIntegration: true,}),... 其它配置 ...],... 其它配置 ...server: {open: false, // 調試桌面應用時務必置為falsehost: '0.0.0.0', // ip地址port: 5173, // 啟動端口... 其它配置 ...},};
});

3.項目根目錄下創建electron目錄,并新建main.js、preload.js文件,main.js對應的是package.json中main字段的值

① main.js內容如下:

const { app, BrowserWindow, ipcMain, shell } = require('electron')
const path = require('path')
const isDev = !app.isPackaged// 安全設置
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'let mainWindowasync function createWindow() {mainWindow = new BrowserWindow({width: 1200,height: 800,minWidth: 800,minHeight: 600,show: true,webPreferences: {preload: path.join(__dirname, 'preload.js'),sandbox: true,contextIsolation: true,nodeIntegration: false,webSecurity: false // 啟用web安全策略}})// 優雅加載mainWindow.once('ready-to-show', () => {mainWindow.show()if (isDev) {mainWindow.webContents.openDevTools({ mode: 'detach' })}})// 安全策略:阻止外部鏈接在應用內打開mainWindow.webContents.setWindowOpenHandler(({ url, frameName, features }) => {console.log(`嘗試打開: ${url}, 框架名: ${frameName}, 特性: ${features}`)if (!url.startsWith('https://')) {shell.openExternal(url) // 使用外部瀏覽器打開return { action: 'deny' }}return { action: 'allow' } // 使用桌面應用新窗口形式打開})// 加載應用if (isDev) {require('electron-reload')/*(__dirname, {electron: path.join(__dirname, 'node_modules', '.bin', 'electron'),hardResetMethod: 'exit'})*/// 加載瀏覽器安全策略// mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {// 	callback({// 		responseHeaders: {// 			...details.responseHeaders,// 			'Content-Security-Policy': [// 				`default-src 'self' 'unsafe-inline' data:;// 				 script-src 'self' 'unsafe-eval' 'unsafe-inline' http:;// 				 connect-src 'self' ws://admin-test-api.ok-yi.com:* http://8.217.215.97:* https://admin-test-api.ok-yi.com:* https://admin-test-api.ok-yi.com:*;// 				 img-src 'self' data: http:;// 				 style-src 'self' 'unsafe-inline';// 				 font-src 'self' data:;`// 			]// 		}// 	})// })await mainWindow.loadURL('http://localhost:5173') // 啟動端口5173務必與vite.config.js中保持一致} else {// vue3+vite項目默認構建產物在根目錄的dist下await mainWindow.loadFile(path.join(__dirname, '../dist/index.html'))}// 開發工具if (isDev) {const { default: installExtension, VUEJS_DEVTOOLS } = require('electron-devtools-installer')try {await installExtension(VUEJS_DEVTOOLS)} catch (e) {console.error('Vue Devtools failed to install:', e.toString())}}
}// 安全通信通道
ipcMain.handle('get-app-version', () => {return app.getVersion()
})app.whenReady().then(() => {createWindow().then(r => {})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow().then(r => {})
})

② preload.js內容如下:

const { contextBridge, ipcRenderer } = require('electron')// 安全暴露有限的API給渲染進程
contextBridge.exposeInMainWorld('electronAPI', {getAppVersion: () => ipcRenderer.invoke('get-app-version'),// openExternal: (url) => {// 	console.log('openExternal = ', url)// 	ipcRenderer.send('open-external', url)// },platform: process.platform
})

4.在App.vue中新增內容,獲取electron主進程暴露給渲染進程的api,內容如下:

<template>
<!--	<el-config-provider :locale="zhCn"><router-view></router-view></el-config-provider>--><div><p>App Version: {{ appVersion }}</p><p>Platform: {{ platform }}</p><button @click="openDocs">Open Docs</button></div>
</template>
<script setup>
// import zhCn from 'element-plus/lib/locale/lang/zh-cn';
import { ref, onMounted } from 'vue'const appVersion = ref('')
const platform = ref('')onMounted(async () => {if (window.electronAPI) {appVersion.value = await window.electronAPI.getAppVersion()platform.value = window.electronAPI.platform}
})const openDocs = () => {if (window.electronAPI) {// window.electronAPI.openExternal('https://electronjs.org/docs')// window.open打開的外部鏈接會通過electron main.js中mainWindow.webContents.setWindowOpenHandler去過濾是使用窗口形式打開還是瀏覽器形式打開window.open('https://electronjs.org/docs')} else {window.open('https://electronjs.org/docs', '_blank')}
}
</script><style scoped></style>

5.一切準備就緒,接下來就可以運行跑起來了

確保已執行 pnpm install且成功安裝所有依賴,執行命令:pnpm run electron:dev 桌面窗口正常彈出來了同時出現的還有調試工具,如下圖:

打包構建使用命令:pnpm run electron:build,本人是用的mac,打包后產物如下圖:

結尾:game over!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76711.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76711.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76711.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(51單片機)串口通訊(串口通訊教程)(串口接收發送教程)

前言&#xff1a; 今天有兩個項目&#xff0c;分別為&#xff1a; 串口接收: 串口發送&#xff1a; 如上圖將文件放在Keli5 中即可&#xff0c;然后燒錄在單片機中就行了 燒錄軟件用的是STC-ISP&#xff0c;不知道怎么安裝的可以去看江科大的視頻&#xff1a; 【51單片機入門…

《汽車制造技術基礎》第一次作業

作業內容 查閱相關資料&#xff0c;談談對汽車制造技術的發展的理解。 可以是關于汽車的先進制造技術 或 汽車先進制造技術 與 制造理念的發展趨勢 或 汽車先進制造技術對環境與可持續發展的影響等。 以下從技術突破、制造理念轉型及環境影響三個維度展開對汽車制造技…

Scala day4(tuple, set and map)

Foreword Hi!! my dear friends, are you lazy at today?? Oh! I am also lazy sometimes, but you will know keep study that’s a right way at last. Now!! let’s start new travel about Scala. Text The all Codes in file day3.scala, like the below program: i…

docker compose搭建博客wordpress

一、前言 docker安裝等入門知識見我之前的這篇文章 https://blog.csdn.net/m0_73118788/article/details/146986119?fromshareblogdetail&sharetypeblogdetail&sharerId146986119&sharereferPC&sharesourcem0_73118788&sharefromfrom_link 1.1 docker co…

第二期:[特殊字符] 深入理解MyBatis[特殊字符]MyBatis基礎CRUD操作詳解[特殊字符]

前言 &#x1f31f; 在掌握了 MyBatis 的基本配置與環境搭建之后&#xff0c;接下來的重點便是深入理解其核心功能——CRUD 操作&#xff08;增刪改查&#xff09;。&#x1f4bb; 數據庫操作是任何應用開發中不可或缺的一環&#xff0c;而 MyBatis 正是通過靈活的 SQL 映射機…

Java面試黃金寶典46

1. Python 如何寫爬蟲 定義:Python 爬蟲是借助 Python 語言編寫程序,模擬瀏覽器行為向目標網站發送 HTTP 請求,獲取網頁內容,再通過解析工具提取所需數據的程序。其本質是自動化的數據采集過程。要點: 發送請求:利用requests庫發送 HTTP 請求,如 GET、POST 等,獲取網頁…

建設“大數據智慧招商平臺”,助力園區突破招商瓶頸!

在數字經濟高速發展的今天&#xff0c;傳統招商模式正面臨信息不對稱、效率低下、匹配不精準等瓶頸。產業園區作為區域經濟發展的核心載體&#xff0c;亟需借助智能化手段提升招商效能。構建大數據智慧招商平臺&#xff0c;利用大數據、人工智能等技術獲取精準招商線索、促進產…

Vue事件修飾符課堂練習

Vue事件修飾符課堂練習 題目?&#xff1a;基于 Vue 2.0&#xff0c;使用事件修飾符 .stop、.prevent、.capture、.self 和 .once&#xff0c;為按鈕綁定 click 事件&#xff0c;并展示每個修飾符的作用。 要求?&#xff1a; 創建一個 Vue 實例&#xff0c;并綁定到一個 HT…

【C#】線程回調

在 C# 中&#xff0c;線程回調是一種常見的編程模式&#xff0c;用于在線程完成任務后執行某些操作。通過使用 Thread 類或其他更高層次的并發工具&#xff08;如 Task&#xff09;&#xff0c;可以實現線程回調的功能。 回調機制 特點 直接性&#xff1a;回調通常是通過委托…

【C++游戲引擎開發】第14篇:視圖空間與相機坐標系

一、視圖空間的基礎數學框架 1.1 齊次坐標與變換矩陣 三維坐標系變換采用44齊次坐標矩陣,其通用形式為: M = [ A 3 3 b 3 1 0 1 3 1 ] \mathbf{M} = \begin{bmatrix} \mathbf{A}_{33} & \mathbf{b}_{31} \\ \mathbf{0}_{13} & 1 \end{bmatrix} M=[A33?013??…

【大模型理論篇】關于生成式模型中聯合分布概率學習必要性以及GPT是生成式模型的討論

1. 背景 之前我們在《生成式模型與判別式模型對比(涉及VAE、CRF的數學原理詳述)》以及《生成式模型算法原理深入淺出&#xff08;涉及Stable Diffusion、生成對抗網絡、高斯混合模型、隱馬爾可夫模型、樸素貝葉斯等算法原理分析及生成式模型解釋&#xff09;》中&#xff0c;我…

DIP支付方式改革下各種疾病醫療費用的影響以及分析方法研究綜述

DIP支付方式改革下各種疾病醫療費用的影響以及分析方法研究綜述 摘要 本文綜述了DIP支付方式改革對不同疾病醫療費用的影響及其分析方法&#xff0c;通過分析12篇相關文獻&#xff0c;探討了DIP支付方式在控制醫療費用、優化費用結構、提升醫療服務效率等方面的作用及其局限性…

嵌入式硬件篇---單片機周期

文章目錄 前言 前言 在單片機中&#xff0c;時序控制是其執行指令和協調外設的核心基礎。以下是單片機中常見的各種周期及其詳細說明&#xff0c;以層次結構展開&#xff1a; 時鐘周期&#xff08;Clock Cycle&#xff09; 定義&#xff1a; 時鐘周期是單片機的最小時間單位&a…

游戲引擎學習第221天:(實現多層次過場動畫)

資產: intro_art.hha 已發布 在下載頁面&#xff0c;你會看到一個新的藝術包。你將需要這個藝術包來進行接下來的開發工作。這個藝術包是由一位藝術家精心制作并打包成我們設計的格式&#xff0c;旨在將這些藝術資源直接應用到游戲中。它包含了許多我們會在接下來的直播中使用…

【3GPP核心網】【5G】精講5G系統的策略和計費控制框架

1. 歡迎大家訂閱和關注,精講3GPP通信協議(2G/3G/4G/5G/IMS)知識點,專欄會持續更新中.....敬請期待! 目錄 1. 系統架構 1.1 非漫游架構 1.2 漫游架構 1.3 支持Rx接口 2. 服務化接口及參考點 2.1 PCF 與 AF 間接口 2.2 PCF與SMF間接口 2.3 PCF與AMF間接口 2.4 V-PC…

榕壹云門店管理系統:基于Spring Boot+Mysql+UniApp的智慧解決方案

項目背景&#xff1a;數字化賦能服務行業&#xff0c;破解傳統門店管理痛點 在消費升級與數字化轉型浪潮下&#xff0c;傳統服務行業&#xff08;如美容、美發、美甲、采耳等&#xff09;面臨諸多管理挑戰&#xff1a;會員流失率高、預約排班混亂、員工績效統計低效、數據孤島等…

開發效率提升200%——cursor

cursor帶來的編程"革命" 高級語言編程轉為"自然語言編程"借助cursor&#xff0c;直接超越初級后臺開發、超越初級前端開發、超越初級測試、超越初級UI&#xff0c;產研一體linux命令只用學不用記&#xff0c;語言描述就是命令給一個表結構流程提示詞&…

UE4 踩坑記錄

1、Using git status to determine working set for adaptive non-unity build 我刪除了一個沒用的資源&#xff0c;結果就報這個錯&#xff0c;原因就是這條命令導致的&#xff0c; 如果這個項目是git項目&#xff0c; ue編譯時會優先通過 git status檢查哪些文件被修改&#…

藍橋杯 2025 C++組 省 B 題解

可分解的正整數 算法&#xff1a;思維 因為可以有負數 所以除了1以外的任何數都可以構造 當這個數為x構造方法為 -(x-1) -(x-2) -(x-3) ....-1 0 1...x-3 x-2 x-1 x 除了x&#xff0c;x以前的數都會被負數抵消 #include <bits/stdc.h> #define ll long long ll a…

docker創建容器添加啟動--restart選項

一、通過 Docker 命令直接修改已啟動的容器&#xff08;推薦-已驗證&#xff09; 操作步驟&#xff1a; 1.執行更新命令&#xff1a; docker update --restartalways <容器名或ID>此命令會將容器的重啟策略調整為 always&#xff08;無論容器以何種狀態退出&#xff0…