vue3 + vite + ts + pinia + electron
构建vite项目
npm
npm init vite@latest
yarn
yarn create vite
选择 vue + 自定义选择
安装依赖
cd aaa
npm install
npm run dev
package.json 解析
{
"scripts": {
"dev": "vite", // 启动开发服务器,别名:`vite dev`,`vite serve`
"build": "vite build", // 为生产环境构建产物
"preview": "vite preview" // 本地预览生产构建产物
}
}
安装脚手架
npm install @vue/cli -g
安装electron
npm install electron --save-dev
npm install vite-plugin-electron --save-dev
npm install electron-builder --save-dev
添加文件 electron/index.ts
index.ts创建window,相当于之前的main.js
import { app, BrowserWindow } from 'electron'
import path from 'path'
//app 控制应用程序的事件生命周期。
//BrowserWindow 创建并控制浏览器窗口。
let win: BrowserWindow | null
//定义全局变量获取 窗口实例
const createWindow = () => {
win = new BrowserWindow({
//
webPreferences: {
devTools: true,
contextIsolation: false,
nodeIntegration: true
//允许html页面上的javascipt代码访问nodejs 环境api代码的能力(与node集成的意思)
}
})
console.log(app.isPackaged)
if (app.isPackaged) {
// win.loadFile(`file://${path.join(__dirname, '../dist/index.html')}`)
win.loadFile(`${path.join(__dirname, '../dist/index.html')}`)
} else {
console.log(
process.env['VITE_DEV_SERVER_HOSTNAME'],
process.env['VITE_DEV_SERVER_PORT'],
process.env['VITE_DEV_SERVER_URL'],
`http://${process.env['VITE_DEV_SERVER_HOSTNAME']}:${process.env['VITE_DEV_SERVER_PORT']}`
)
//VITE_DEV_SERVER_HOST 如果是undefined 换成 VITE_DEV_SERVER_HOSTNAME
win.loadURL(
`${process.env['VITE_DEV_SERVER_URL']}`
// `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`
// `http://localhost:5173`
)
}
}
//isPackage 不好使换下面的
// if(process.env.NODE_ENV != 'development'){
// win.loadFile(path.join(__dirname, "../index.html"));
// }else{
//win.loadURL(`http://${process.env['VITE_DEV_SERVER_HOSTNAME']}:${process.env['VITE_DEV_SE//RVER_PORT']}`)
// }
//在Electron完成初始化时被触发
app.whenReady().then(createWindow)
或者electron/index.js
如果 __dirname 报错则 添加
import path from 'path'
import {fileURLToPath} from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
import { app, BrowserWindow } from 'electron'
import path from 'path'
//app 控制应用程序的事件生命周期。
//BrowserWindow 创建并控制浏览器窗口。
let win //: BrowserWindow | null
//定义全局变量获取 窗口实例
const createWindow = () => {
win = new BrowserWindow({
//
webPreferences: {
devTools: true,
contextIsolation: false,
nodeIntegration: true,
// eslint-disable-next-line no-undef
// preload: path.join(__dirname, '../dist-electron/preload.js')
// eslint-disable-next-line no-undef
preload: path.join(__dirname, './preload.js')
// preload: '../electron/preload.js'
//允许html页面上的javascipt代码访问nodejs 环境api代码的能力(与node集成的意思)
}
})
console.log(app.isPackaged)
win.setMenuBarVisibility(false) // 隐藏菜单栏
if (app.isPackaged) {
// win.loadURL(`file://${path.join(__dirname, '../dist/index.html')}`)
// win.loadFile(`file://${path.join(__dirname, '../dist/index.html')}`)
// eslint-disable-next-line no-undef
win.loadFile(path.join(__dirname, '../dist/index.html'))
} else {
//VITE_DEV_SERVER_HOST 如果是undefined 换成 VITE_DEV_SERVER_HOSTNAME
win.loadURL(
// eslint-disable-next-line no-undef
`${process.env['VITE_DEV_SERVER_URL']}`
// `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`
// `http://localhost:5173`
)
}
}
//isPackage 不好使换下面的
// if(process.env.NODE_ENV != 'development'){
// win.loadFile(path.join(__dirname, "../index.html"));
// }else{
//win.loadURL(`http://${process.env['VITE_DEV_SERVER_HOSTNAME']}:${process.env['VITE_DEV_SE//RVER_PORT']}`)
// }
//在Electron完成初始化时被触发
app.whenReady().then(createWindow)
添加electron/preload.js
package.json中删除
{
"type": "module",
"main": "electron/index.js",
}
添加
{
"main": "dist-electron/index.js",
}
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
// eslint-disable-next-line no-undef
const { ipcRenderer } = require('electron')
window.addEventListener('DOMContentLoaded', () => {
console.log('loaded', window, ipcRenderer) // // const replaceText = (selector, text) => {
window.ipcRenderer = ipcRenderer
})
// /** docoment 加载完成 */
function domReady(...args) {
const condition = args.length ? [...args] : ['complete', 'interactive']
return new Promise((resolve) => {
if (condition.includes(document.readyState)) {
resolve(true)
} else {
document.addEventListener('readystatechange', () => {
if (condition.includes(document.readyState)) {
resolve(true)
}
})
}
})
}
;(async function () {
await domReady()
console.log('domReady', window, ipcRenderer)
// window.ipcRenderer = require('electron').ipcRenderer;
window.ipcRenderer = ipcRenderer
})()
添加 vite.config.electron.ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import electron from 'vite-plugin-electron'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
electron({ entry: ['electron/index.ts', 'electron/preload.ts'] })
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
修改package.json
{
"main": "dist-electron/index.js",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"build-client": "vue-tsc --noEmit && vite build --config vite.config.electron.ts && electron-builder",
"dev-client": "vue-tsc --noEmit && vite --config vite.config.electron.ts && electron .",
"preview": "vite preview",
"test:unit": "vitest",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
}
package.json 中build配置
{
"build": {
"productName": "package",
"copyright": "",
"directories": {
"output": "release/"
},
"files": [
"dist",
"dist-electron",
"release"
],
"mac": {
"artifactName": "${productName}_${version}.${ext}",
"target": [
"dmg"
]
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
],
"artifactName": "${productName}_${version}.${ext}"
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": false,
"installerIcon": "./electron/induSec-logo.ico",
"uninstallerIcon": "./electron/induSec-logo.ico"
},
"publish": [
{
"provider": "generic",
"url": "http://127.0.0.1:8080"
}
],
"releaseInfo": {
"releaseNotes": "版本更新的具体内容"
}
}
}
nsis(桌面应用程序安装过程)配置
{
// 一键安装程序、或者辅助安装程序(默认是一键安装)
"oneClick": false,
// 是否允许请求提升,如果为 false,则用户必须使用提升的权限重新启动安装程序(仅作用于辅助安装程序)
"allowElevation": true,
// 是否允许修改安装目录(仅作用于辅助安装程序)
"allowToChangeInstallationDirectory": true,
// 安装程序图标的路径
"installerIcon": "public/timg.ico",
// 卸载程序图标的路径
"uninstallerIcon": "public/timg.ico",
// 安装时头部图片路径(仅作用于辅助安装程序)
"installerHeader": "public/timg.ico",
// 安装时标题图标(进度条上方)的路径(仅作用于一键安装程序)
"installerHeaderIcon": "public/timg.ico",
// 安装完毕界面图片的路径,图片后缀.bmp,尺寸 164*314(仅作用于辅助安装程序)
"installerSidebar": "public/installerSiddebar.bmp",
// 开始卸载界面图片的路径,图片后缀.bmp,尺寸 164*314(仅作用于辅助安装程序)
"uninstallerSidebar": "public/uninstallerSiddebar.bmp",
// 控制面板中的卸载程序显示名称
"uninstallDisplayName": "${productName}${version}",
// 是否创建桌面快捷方式
"createDesktopShortcut": true,
// 是否创建开始菜单快捷方式
"createStartMenuShortcut": true,
// 用于快捷方式的名称,默认为应用程序名称
"shortcutName": "TestApp",
// NSIS 包含定制安装程序脚本的路径,安装过程中自行调用 (可用于写入注册表 开机自启动等操作)
"include": "script/installer.nsi",
// 用于自定义安装程序的 NSIS 脚本的路径
"script": "script/installer.nsi",
// 是否在卸载时删除应用程序数据(仅作用于一键安装程序)
"deleteAppDataOnUninstall": false,
// 完成后是否运行已安装的应用程序(对于辅助安装程序,应删除相应的复选框)
"runAfterFinish": true,
// 是否为开始菜单快捷方式和程序文件目录创建子菜单,如果为 true,则使用公司名称
"menuCategory": false,
}
electron 镜像下载保存位置
根据需要的版本下载
macOS: ~/Library/Caches/electron
Linux: ~/.chche/electron
windows: %/LOCALAPPDATA%/electron/cache
window C:/Users/用户名/AppData/local/electron
nsis 保存到 C:/Users/用户名/AppData/local/electron-builder/Cache
cross-env
安装 cross-env,这个包用来设置环境变量
修改package.json, "dev": "cross-env NODE_ENV=development vite",这样就指定开发时的环境变量,
修改electron/index.ts, process.env.NODE_ENV !='development' 判断生产环境
默认白屏问题
路由地址为空,或者需要点击跳转路由才可看到页面
修改vue路由类型改为hash
const router = createRouter({
history: createWebHashHistory(), // 由 createWebHistory() 改为hash
routes: [
{
path: '/',
name: 'login',
component: () => import('@/views/login/index.vue')
}
]
})