尝鲜electron --将已有vue/react项目转换为桌面应用

Electron 是一个强大的框架,它允许开发者使用 Web 技术(如 HTML、CSS 和 JavaScript)构建跨平台的桌面应用程序。它结合了 Node.js 和 Chromium,就相当于在桌面程序=web和游览器,所以只需要简单的配置就可以转换为桌面应用

注意:无关镜像,有些依赖就是需要从git上面手动下载,所以特别是打包模块,需要一步一步下载手动安装

转换为桌面app

添加依赖

bash 复制代码
yarn add --dev electron

如果下载失败 根据输出的连接手动添加到用户的eletron目录

bash 复制代码
C:\Users用户名\AppData\Local\electron\Cache

在已有的根项目(这里是vite+vue)创建一个

electron文件夹并且创建俩个文件,一个主进程文件,一个预加载文件

.env.development 写开发端口地址

js 复制代码
#有些版本不写node_env 属性的话无法根据这个后缀识别
VITE_DEV_SERVER_URL=http://localhost:3000
API=XXXXX

生产环境**.env.production**

js 复制代码
NODE_ENV=production
VITE_DEV_SERVER_URL=http://服务器地址:3000
API=XXXXX

.env 文件 指定模式

js 复制代码

如果不能识别 env 环境的需要安装一些toenv工具

bash 复制代码
yarn add dotenv

electron的主进程文件
main.js

js 复制代码
const { app, BrowserWindow, ipcMain, Menu, Notification, dialog, globalShortcut } = require('electron')
const { console } = require('inspector')
const path = require('path')

const dotenv = require('dotenv');

// 根据当前环境选择 .env 文件
// 首先加载 .env 文件,以确保 process.env.NODE_ENV 被设置
dotenv.config({ path: '.env' });

// 输出当前的 NODE_ENV 以进行验证
console.log('Initial process.env.NODE_ENV:', process.env.NODE_ENV);

// 根据当前环境选择 .env 文件
let envPath;
if (process.env.NODE_ENV === 'production') {
    envPath = '.env.production';
} else {
    envPath =  '.env.development';
}

// 再次加载特定环境的 .env 文件
dotenv.config({ path: envPath });
// 加载环境变量
// dotenv.config({ path: '.env.development' });
// 定义主窗口的全局变量

let mainWindow
let isDev = process.env.NODE_ENV === 'development'
//校验环境是否可以被加载
console.log('process.env.NODE_ENV:', process.env.NODE_ENV)
console.log('isDev:', isDev)
console.log('VITE_DEV_SERVER_URL:', process.env.VITE_DEV_SERVER_URL)
console.log('VITE_DEV_SERVER_URL:', process.env.VITE_DEV_SERVER_URL)
// 创建窗口
function createWindow() {
    // 输出 VITE_DEV_SERVER_URL 环境变量值
    mainWindow = new BrowserWindow({
        title: 'Electron 应用示例',
        icon: path.join(__dirname, '../public/icon.png'),
        width: 1000,
        height: 800,
        minWidth: 800,
        minHeight: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            nodeIntegration: false, // 增加安全性,尽量设为 false
            contextIsolation: true, // 隔离上下文,提高安全性
            enableRemoteModule: false // 禁用 remote 模块,提高安全性
        }
    })
    // 根据环境加载页面
    if (isDev) {
        console.log('开发环境')
        // 开发环境
        mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL) 
        // mainWindow.webContents.openDevTools() // 打开开发者工具


    } else {
        // 生产环境
        mainWindow.loadFile(path.join(__dirname, '../dist/index.html')).then(() => {
            console.log('加载生产环境文件1')
        })
    }

    // 窗口关闭事件
    mainWindow.on('closed', () => {
        mainWindow = null
    })
}

// 设置全局快捷键
function setupGlobalShortcuts() {
    globalShortcut.register('CommandOrControl+R', () => {
        if (mainWindow) {
            mainWindow.reload()
        } // 刷新窗口
    })
    globalShortcut.register('F12', () => {
        if (mainWindow) {
            mainWindow.webContents.toggleDevTools()
        } // 切换开发者工具
    })
}

// 创建菜单栏(MacOS 默认菜单)
const isMac = process.platform === 'darwin'
const template = [
    ...(isMac ? [{ role: 'appMenu' }] : []),
    { role: 'fileMenu' },
    { role: 'editMenu' },
    { role: 'viewMenu' },
    {
        label: '帮助',
        submenu: [
            {
                label: '关于',
                click: async () => {
                    await dialog.showMessageBox({
                        type: 'info',
                        title: '关于',
                        message: '这是一个基于 Electron 的应用示例'
                    })
                }
            },
            {
                label: '检查更新',
                click: async () => {
                    await dialog.showMessageBox({
                        type: 'info',
                        title: '检查更新',
                        message: '暂不支持自动更新'
                    })
                }
            },
            {
                label: '日志',
                click: async () => {
                    await dialog.showMessageBox({
                        type: 'info',
                        title: '日志',
                        message: '暂无日志'
                    })
                }
            }
        ]
    }
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

// 监听与渲染进程的 IPC 通信
ipcMain.handle('show-notification', async (event, message) => {
    new Notification({ title: '通知', body: message }).show()
})

// 应用生命周期事件
app.on('ready', () => {
    createWindow()
    setupGlobalShortcuts() // 注册全局快捷键
    console.log('应用已准备完毕')
})

app.on('window-all-closed', () => {
    // macOS 平台上关闭最后一个窗口时不退出应用
    if (!isMac) {
        app.quit()
    }
})

app.on('activate', () => {
    // macOS 平台上重新激活应用时重新创建窗口
    if (mainWindow === null) {
        createWindow()
    }
})

app.on('will-quit', () => {
    globalShortcut.unregisterAll() // 取消所有注册的快捷键
})

// 捕获未捕获的异常,便于调试
process.on('uncaughtException', error => {
    console.error('未捕获的异常:', error)
})

// 处理用户请求的文件打开事件(macOS 平台支持文件拖放打开)
app.on('open-file', (event, filePath) => {
    event.preventDefault()
    console.log(`打开文件:${filePath}`)
    if (mainWindow) {
        mainWindow.webContents.send('file-opened', filePath)
    }
})

这里做了动态渲染本地运行的网页还是打包后的网页

当然也可以直接设置development ,和production

并不是鸡肋,目的是打包后为了测试是否可以正常渲染

preload.js

js 复制代码
// 所有Node.js API都可以在预加载过程中使用。
// 它拥有与Chrome扩展一样的沙盒。
window.addEventListener('DOMContentLoaded', () => {
    const replaceText = (selector, text) => {
        const element = document.getElementById(selector)
        if (element) element.innerText = text
    }

    for (const dependency of ['chrome', 'node', 'electron']) {
        replaceText(`${dependency}-version`, process.versions[dependency])
    }
})
  1. 然后在package。json
    添加指令 注意有type :"moddule"的话会报错 需要注释
json 复制代码
  "main": "electron/main.js",
 "electron": "electron .",
 "scripts": {
   "dev": "vite",
   "start": "electron .",

3.先运行项目 然后 yarn start

打包

打包设置

配置build 报答的各个属性 output打包后的安装包输出目录

js 复制代码
  "scripts": {
    "dev": "vite",
    "start": "electron .",
    "electron:build": " vite build && electron-builder",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    "lint": "eslint --fix --ext .vue,.jsx,.ts,.tsx ."
  },
  "build": {
    "electronDownload": {
      "mirror": "https://npm.taobao.org/mirrors/electron/"
    },
    "appId": "com.example.app",
    "productName": "版本管理系统",
    "files": [
      "dist/**/*",
      "electron/**/*"
    ],
    "directories": {
      "output": "setup",
      "buildResources": "build"
    },
    "win": {
      "icon": "asset/NSHM_PHOTO_2024_7_24_03_01_45.jpg" ,
      "target": [
        "nsis"
      ]
    },
    "nsis": {
      "oneClick": false,
      "perMachine": true,
      "allowToChangeInstallationDirectory": true
    }
  },

1.下载依赖

bash 复制代码
npm install electron electron-builder --save-dev

这里开始这个打包的东西就感觉很慢了 可以根据console 控制台输出手动下载

如果下载失败

可以手动下载 放在目录

bash 复制代码
C:\Users\用户名\AppData\Local\electron-builder\Cache

winCodeSign-2.6.0 下载失败 ,复制手动下载

然后这个cache目录新建winCodeSign文件夹 然后把压缩包进入进行解压

针对 nsis-3.0.4.1 下载失败:

同理复制console报错的地址下载完成后,新建nis文件夹然后:nsis解压

nsis-resourcers-3.4.1

同理下载后 在刚才的创建nsis目录解压

此时可以运行package.json 配置的打包指令

yarn electron:build

此时控制台会报错,但是配置的setup文件夹已经有安装程序了

使用electron forge 打包

官方文档

当前版本官方推荐的是electron forge
安装

bash 复制代码
yarn add --dev @electron-forge/cli
npx electron-forge import
相关推荐
初遇你时动了情12 分钟前
react 项目打包二级目 使用BrowserRouter 解决页面刷新404 找不到路由
前端·javascript·react.js
码农老起38 分钟前
掌握 React:组件化开发与性能优化的实战指南
react.js·前端框架
前端没钱1 小时前
从 Vue 迈向 React:平滑过渡与关键注意点全解析
前端·vue.js·react.js
顽疲2 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端
羊小猪~~2 小时前
前端入门之VUE--ajax、vuex、router,最后的前端总结
前端·javascript·css·vue.js·vscode·ajax·html5
摸鱼了2 小时前
🚀 从零开始搭建 Vue 3+Vite+TypeScript+Pinia+Vue Router+SCSS+StyleLint+CommitLint+...项目
前端·vue.js
2401_857600953 小时前
基于 SSM 框架 Vue 电脑测评系统:赋能电脑品质鉴定
前端·javascript·vue.js
天之涯上上3 小时前
Pinia 是一个专为 Vue.js 3 设计的状态管理库
前端·javascript·vue.js
高山我梦口香糖4 小时前
[react] <NavLink>自带激活属性
前端·javascript·react.js
撸码到无法自拔4 小时前
React:组件、状态与事件处理的完整指南
前端·javascript·react.js·前端框架·ecmascript