目录

1. Electron 介绍

2. 使用 Vite 构建 Electron 项目

2.1 创建 Vite 应用,安装 Electron 依赖

2.2 在 vite.config.ts 中,配置 Electron 入口文件

2.3 编写 electron / index.ts

2.3.1 app、BrowserWindow

2.3.2 使用 win.loadURL 加载窗口 / Vite 环境变量

2.3.3 使用 app.whenReady() 初始化app

2.3.4 整理 electron / index.ts

2.4 配置 package json,运行项目

2.4.1 运行项目后,出现的两个报错

2.4.2 开发环境运行效果

3. 打包 Electron 桌面程序

3.1 安装打包依赖,调整打包命令

3.2 修改 electron / index.ts,判断当前环境

3.3 修改 package.json

3.3.1 增加 electron-builder 相关配置

3.3.2 nsis(桌面应用程序安装过程)配置一览

3.4 执行打包,安装应用

3.5 解决 Electron 启动后白屏、在控制台中输出乱码

3.5.1 Electron 启动后白屏

3.5.2 主进程接收渲染进程消息时,在控制台输出乱码

4. 实现 渲染进程 / 主进程 通信(IPC)

4.1 让 Vite 支持 ipcRenderer

4.2 渲染进程发送消息,主进程接收消息

4.3 主进程发送消息,渲染进程接收消息

5. 参考视频


1. Electron 介绍

Build cross-platform desktop apps with JavaScript, HTML, and CSS | ElectronBuild cross-platform desktop apps with JavaScript, HTML, and CSShttps://www.electronjs.org/

Electron 内置了 Chromium 和 Node.js:

  • Chromium 是渲染进程,用于渲染、解析 HTML
  • Node.js 是主进程
  • 渲染进程 / 主进程,使用 IPC 进行通信

VsCode 是 Electron 开发的桌面程序

2. 使用 Vite 构建 Electron 项目

2.1 创建 Vite 应用,安装 Electron 依赖

创建一个 Vite 项目

npm init vite@latest

 

安装 Electron 相关依赖

npm install electron -D
npm install vite-plugin-electron -D 

温馨提示:vite 中支持 Electron 的插件也改为 vite-electron-plugin,就是第二条安装命令

vite-electron-plugin - npmFast, Electron plugin for Vite. Latest version: 0.5.2, last published: 20 days ago. Start using vite-electron-plugin in your project by running `npm i vite-electron-plugin`. There are no other projects in the npm registry using vite-electron-plugin.https://www.npmjs.com/package/vite-electron-plugin

2.2 在 vite.config.ts 中,配置 Electron 入口文件

 

根据上方官网提示,创建 electron / index.ts,与 src 目录同级

配置 Electron 入口文件 —— 打开 vite.config.ts,引入 electron / index.ts

这么配置,就启动一个 Vite 应用就行,就不需要启动 Electron + Vite 了

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import electron from 'vite-plugin-electron'

export default defineConfig({
  plugins: [vue(), electron({
    main: {
      // 配置 Electron 入口文件
      entry: "electron/index.ts"
    }
  })]
})

 

注意:vite-plugin-electron 0.10.4 中,使用 main 会报错,得这么写

electron({
    // main: {
    //   entry: "electron/index.ts"
    // }
    entry: "electron/index.ts"
})

2.3 编写 electron / index.ts

2.3.1 app、BrowserWindow

在 electron 依赖中,可以引入 app、BrowserWindow:

  • app 控制应用程序的事件生命周期(相当于应用程序)
  • BrowserWindow 创建并控制浏览器窗口(相当于打开桌面弹框)

 

实例化 BrowserWindow 对象,创建一个窗口,在内部通过 nodeIntegration、contextIsolation 集成网页和 Node.js(也就是在渲染进程中,可以调用 Node.js 方法)

2.3.2 使用 win.loadURL 加载窗口 / Vite 环境变量

使用 win.loadURL 加载窗口,接收的网址是指:Vite 启动后,会在本地运行一个服务,把这个服务网址丢进去就行

  • 使用 Vite 自带的环境变量 VITE_DEV_SERVER_HOST
  • 如果是 undefined,就换成 VITE_DEV_SERVER_HOSTNAME(现在应该采用这个了)
  • ps:在 Vite 3.2.41中,使用 VITE_DEV_SERVER_URL 表示 Vite 服务器本地路径

 Vite | 下一代的前端工具链下一代前端工具链https://cn.vitejs.dev/

 

关于 Vite 环境变量,可以去终端看下

 

2.3.3 使用 app.whenReady() 初始化app

最后,使用 app.whenReady() 初始化app(在 Electron 完成初始化时触发)

初始化完成后,再挂载上面创建的 桌面应用程序窗口

2.3.4 整理 electron / index.ts

在 electron / index.ts 中,写入下方代码

// app 控制应用程序的事件生命周期(相当于应用程序)
// BrowserWindow 创建并控制浏览器窗口(相当于打开桌面弹框)
import { app, BrowserWindow } from 'electron'
import path from 'path'

// 定义全局变量,获取窗口实例
let win: BrowserWindow | null;

/**
 * 创建一个窗口
 */
const createWindow = () => {
  win = new BrowserWindow({
    webPreferences: {
      devTools: true,
      // 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
      nodeIntegration: true,
      contextIsolation: false,
    }
  })
    // 集成网页和 Node.js 后,需要加载
    // 这里接收的网址是指:Vite 启动后,会在本地运行一个服务,把这个服务网址丢进去就行
    // 使用 Vite 自带的环境变量 VITE_DEV_SERVER_HOST
    // 如果是 undefined,就换成 VITE_DEV_SERVER_HOSTNAME
    
win.loadURL(`http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`)
}

// 初始化app(在 Electron 完成初始化时触发),挂载上面创建的 桌面应用程序窗口
app.whenReady().then(createWindow)

2.4 配置 package json,运行项目

2.4.1 运行项目后,出现的两个报错

启动项目后,出现下面两个报错

综上所述,需要在 package.json 中,增加 main 字段,去掉 type 字段

{
  "name": "electron-vite",
  "private": true,
  "version": "0.0.0",
  "main": "dist/electron/index.js",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build  &&  electron-builder",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.2.37"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^3.0.0",
    "electron": "^19.0.10",
    "electron-builder": "^23.1.0",
    "typescript": "^4.6.4",
    "vite": "^3.0.0",
    "vite-plugin-electron": "^0.8.3",
    "vue-tsc": "^0.38.4"
  }
}

2.4.2 开发环境运行效果

运行项目 npm run dev

 

3. 打包 Electron 桌面程序

3.1 安装打包依赖,调整打包命令

安装打包依赖 electron-builder

npm install electron-builder -D 

 

安装完成后,在 package json 中,配置 build 命令

"build": "vue-tsc --noEmit && vite build && electron-builder", 

3.2 修改 electron / index.ts,判断当前环境

打完包之后,还需要修改下 electron / index.ts,因为:

  • 开发环境下,我们访问的是 Vite 本地服务
  • 打包之后,我们访问的是 dist 静态文件

所以要修改 win.loadURL 中的路径参数,判断下当前是生产环境,还是开发环境

修改后的 electron / index.ts 如下

// app 控制应用程序的事件生命周期(相当于应用程序)
// BrowserWindow 创建并控制浏览器窗口(相当于打开桌面弹框)
import { app, BrowserWindow } from 'electron'
import path from 'path'

// 定义全局变量,获取窗口实例
let win: BrowserWindow | null;

/**
 * 创建一个窗口
 */
const createWindow = () => {
  win = new BrowserWindow({
    webPreferences: {
      devTools: true,
      // 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
      nodeIntegration: true,
      contextIsolation: false,
      //允许html页面上的javascipt代码访问nodejs 环境api代码的能力(与node集成的意思)
    }
  })

  // 生产环境、开发环境,访问的路径不同
  // 开发环境下,我们访问的是 Vite 本地服务
  // 打包之后,我们访问的是 dist 静态文件
  // 所以这里要加个判断
  if (app.isPackaged) {
      win.loadFile(path.join(__dirname, "../index.html"));
  } else {
    // 集成网页和 Node.js 后,需要加载
    // 这里接收的网址是指:Vite 启动后,会在本地运行一个服务,把这个服务网址丢进去就行
    // 使用 Vite 自带的环境变量 VITE_DEV_SERVER_HOST
    // 如果是 undefined,就换成 VITE_DEV_SERVER_HOSTNAME
    win.loadURL(`http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`)
  }
}

// 初始化app(在 Electron 完成初始化时触发)
app.whenReady().then(createWindow)

// isPackage 无效,可以换下面的
// 注意:这个环境变量,需要安装 cross-env,在 package.json 中指定下,在 3.5 中写了
// 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']}`)
// }

注意:这里有坑啊,isPackage 在 Electron 中判断 生产环境 / 开发环境,是会出现 bug 的,具体参考下面的 3.5 有解释

3.3 修改 package.json

3.3.1 增加 electron-builder 相关配置

appId、productName... —— 应用基本信息信息

win、mac —— 不同类型设备配置

nsis —— 桌面应用程序安装过程的配置

  "build": {
    "appId": "com.electron.desktop",
    "productName": "electron",
    "asar": true,
    "copyright": "Copyright © 2022 electron",
    // 输出路径
    "directories": {
      "output": "release/"
    },
    "files": [
      "dist"
    ],
    // mac 配置
    "mac": {
      "artifactName": "${productName}_${version}.${ext}",
      "target": [
        "dmg"
      ]
    },
    // windows 配置
    "win": {
      "target": [
        {
          "target": "nsis",
          "arch": [
            "x64"
          ]
        }
      ],
      "artifactName": "${productName}_${version}.${ext}"
    },
    // 应用程序的安装过程配置
    "nsis": {
      // 关闭了一键集成,因此会走 下一步、下一步、下一步... 进行安装
      "oneClick": false,
      "perMachine": false,
      "allowToChangeInstallationDirectory": true,
      "deleteAppDataOnUninstall": false
    },
    "publish": [
      {
        "provider": "generic",
        "url": "http://127.0.0.1:8080"
      }
    ],
    "releaseInfo": {
      "releaseNotes": "版本更新的具体内容"
    }
  }

 

3.3.2 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,
}

3.4 执行打包,安装应用

npm run build

打包成功后,生成的文件都放到了 release 目录下(之前在 package.json 里是这么配置的)

双击 exe 结尾的文件,就能运行桌面应用程序了

安装应用

3.5 解决 Electron 启动后白屏、在控制台中输出乱码

3.5.1 Electron 启动后白屏

启动后,发现应用白屏,可以下载 Debugtron 进行调试

发现输出的当前环境是 非生产环境

app. Ispackaged is also false after it is packaged by electronic builder · Issue #35153 · electron/electron · GitHubPreflight Checklist I have read the Contributing Guidelines for this project. I agree to follow the Code of Conduct that this project adheres to. I have searched the issue tracker for a bug report that matches the one I want to file, wit...https://github.com/electron/electron/issues/35153

后面这个问题没有后续了,所以还是先别用 isPackage 那个变量了,可以换种思路:

  • 安装 cross-env,这个包用来设置环境变量
  • 修改 package.json,"dev" : "cross-env NODE_ENV=development vite", 这样就指定了开发时的环境变量,那只要不是开发时,就是生产时
  • 修改 electron / index.ts,process.env.NODE_ENV != 'development' 这么判断生产环境

3.5.2 主进程接收渲染进程消息时,在控制台输出乱码

加上 chcp 65001 输出中文

加上 cross-env NODE_ENV=development 实现自定义开发时的环境变量

 

最终 dev 命令如下:

"dev": "chcp 65001 && cross-env NODE_ENV=development vite",

4. 实现 渲染进程 / 主进程 通信(IPC)

4.1 让 Vite 支持 ipcRenderer

使用 ipcRenderer 进行通信

默认情况下,Vite 不支持 ipcRenderer,得安装插件 vite-plugin-electron-renderer 让他支持

安装 vite-plugin-electron 的时候,就已经同时安装了 vite-plugin-electron-renderer,所以不用重复安装他,直接引入就行

修改 vite.config.ts,不改会报错:Error: Module "path" has been externalized for browser compatibility. Cannot

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import electron from 'vite-plugin-electron'
// 安装 vite-plugin-electron 的时候,就同时安装了 vite-plugin-electron-renderer
import electronRender from 'vite-plugin-electron-renderer'

export default defineConfig({
  plugins: [vue(), electron({
    main: {
      entry: "electron/index.ts"
    }
  }), electronRender()],
  build:{
    emptyOutDir: false,
  }
})

这样,就实现了让 Vite 支持 ipcRenderer

4.2 渲染进程发送消息,主进程接收消息

渲染进程使用 ipcRenderer.send() 发送消息

在 vue 文件中,添加一个按钮,点击后通过 ipcRenderer 给主进程发消息

import { ipcRenderer } from 'electron'
 
const open = () => {
 ipcRenderer.send('openFlyCar')
}

主进程使用 ipcMain.on() 接收消息

在 electron / index.ts 文件中,引入 ipcMain,监听 .vue 文件发出的消息

import { app, BrowserWindow, ipcMain } from 'electron'

// 这段代码在 createWindow 创建窗口函数内执行
ipcMain.on('openFlyCar', () => {
    console.log('收到')
})

 

 

4.3 主进程发送消息,渲染进程接收消息

主进程使用 win.webContents.send() 通知渲染进程消息

const win = new BrowserWindow(xxxxx)
win!.webContents.send('load', { message: "electron初始化了" })

 

渲染进程通过 ipcRenderer.on() 接收主进程发来的消息,会在控制台输出

ipcRenderer.on('load', (_, data) => {
  console.log(data)
})

5. 参考视频

讲的非常非常详细,各种坑都讲到了 

小满Vue3(第三十九章 electron桌面程序)_哔哩哔哩_bilibili小满Vue3(第三十九章 electron桌面程序)是Vue3 + vite + Ts + pinia + 实战 + 源码 +electron的第51集视频,该合集共计110集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV1dS4y1y7vd?p=51&vd_source=8bc01635b95dbe8ecd349b2c23b03a10

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐