Electron 搭建桌面端框架

219 阅读2分钟

vue+vite+electron 搭建步骤

https://blog.csdn.net/weixin_42367460/article/details/129839235

  • 1. 更新npm镜像,安装cnpm(npm和pnpm安装不了electron依赖)

npm config set registry https://registry.npmmirror.com/

npm i cnpm -g --registry=https://registry.npmmirror.com

cnpm config ls 找到配置文件.npmrc添加以下配置

ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/

  • 2. vite脚手架搭建项目

cnpm create vite electron-demo --template vue-ts // 一步创建

cnpm init vue@latest // 配置创建

  • 3. 安装electron和vite-plugin-electron依赖

cnpm i electron vite-plugin-electron -D

  • 4. 创建electron入口

/electron/index.ts

//app 控制应用程序的事件生命周期。
//BrowserWindow 创建并控制浏览器窗口。
import { app, BrowserWindow } from 'electron'
import path from 'path'

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

const createWindow = () => {
  win = new BrowserWindow({
    width: 800,
    height: 600,
    // 是否隐藏菜单,默认 false
    autoHideMenuBar: false,
    //允许html页面上的javascipt代码访问nodejs 环境api代码的能力(与node集成的意思)
    webPreferences: {
      devTools: true,
      contextIsolation: false,
      nodeIntegration: true
    }
  })
  win.loadFile(path.join(__dirname, '../dist/index.html'))
  win.loadURL(`${process.env['VITE_DEV_SERVER_URL']}`)

  // 打开开发者工具
  win.webContents.openDevTools()
}

//在Electron完成初始化时被触发
app.whenReady().then(
  () => {
    createWindow()
   
    app.on('activate', function () {
      // 通常在 macOS 上,当点击 dock 中的应用程序图标时,如果没有其他
      // 打开的窗口,那么程序会重新创建一个窗口。
      if (BrowserWindow.getAllWindows().length === 0) createWindow()
    })
  }
)
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此,通常对程序和它们在
// 任务栏上的图标来说,应当保持活跃状态,直到用户使用 Cmd + Q 退出。
app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})
  • 5.配置vite.config.ts

/vite.config.ts

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    electron({
      // 入口文件
      entry: 'electron/index.ts'
    })
  ],
})
  • 6.配置package json,增加main 字段,去掉 type 字段

/package.json

{
  "name": "electron-vue-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.4.21"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.4",
    "electron": "^29.1.5",
    "typescript": "^5.2.2",
    "vite": "^5.2.0",
    "vite-plugin-electron": "^0.28.4",
    "vue-tsc": "^2.0.6"
  }
}
  • 7.运行项目

cnpm run dev

  • 8.electron-builder打包Electron cnpm i electron-builder -D

win + R 搜索powershell 输入Start-Process powershell -Verb runAs 打开管理员窗口

cd 文件路径

运行 cnpm run build 打包

/package.json

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

/electron-builder.json

{
    // 包名
    appId: 'com.electron.desktop',
    // 项目名 这也是生成的exe文件的前缀名
    productName: 'electron',
    // 是否 用 asar 压缩
    asar: true,
    //版权  信息
    copyright: 'Copyright © 2022 electron',
    directories: {
      // 输出文件夹
      output: 'release/'
    },
    // 被打包的文件
    // build 的 files 中要加dist和dist-electron,
    // dist 是 build vue文件的结果。
    // dist-electron 是 build electron下面的文件的结果。
    files: [
      'dist',
      'dist-electron'
    ],
    mac: {
      //图标路径
      icon: 'https://lmg.jj20.com/up/allimg/1114/050R1105319/21050Q05319-1-1200.jpg',
      artifactName: '${productName}_${version}.${ext}',
      // 我们要的目标安装包
      target: ['dmg']
    },
    // windows相关的配置
    win: {
      //图标路径
      icon: 'https://lmg.jj20.com/up/allimg/1114/050R1105319/21050Q05319-1-1200.jpg',
      // 我们要的目标安装包
      target: [
        {
          target: 'nsis',
          arch: ['x64']
        }
      ],
      artifactName: '${productName}_${version}.${ext}'
    },
    // 自定义一些.exe文件安装过程中的一些操作
    nsis: {
      // 代表是否显示辅助安装程序的安装模式安装程序页面(选择按机器还是按用户)。
      // true时代表始终按用户安装。
      perMachine: false,
      // 创建一键安装程序还是辅助安装程序(默认是一键安装)
      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: 'SHom',
      // NSIS包含定制安装程序脚本的路径,安装过程中自行调用  (可用于写入注册表 开机自启动等操作)
      include: 'script/installer.nsi',
      // 用于自定义安装程序的NSIS脚本的路径
      script: 'script/installer.nsi',
      // 是否在卸载时删除应用程序数据(仅作用于一键安装程序)
      deleteAppDataOnUninstall: false,
      // 完成后是否运行已安装的应用程序(对于辅助安装程序,应删除相应的复选框)
      runAfterFinish: true,
      // 是否为开始菜单快捷方式和程序文件目录创建子菜单,如果为true,则使用公司名称
      menuCategory: false
    },
    // 更新用的配置,主要是为了生成lastest.yaml配置文件
    publish: [
      {
       // 服务器提供商 也可以是GitHub等等
        provider: 'generic',
        // 服务器地址}
        url: 'http://127.0.0.1:6060'
      }
    ],
    releaseInfo: {
      releaseNotes: '版本更新的具体内容'
    }
  }

安装步骤

1. 创建文件夹, 初始化

mkdir my-electron-app && cd my-electron-app
npm init

2. 安装 electron 依赖

npm设置淘宝镜像npm config set registry https://registry.npmmirror.com/

npm install cnpm -g --registry=https://registry.npmmirror.com

cnpm install electron --save-dev

3. 添加 .gitignore 文件

# Dependency directories
node_modules/

4.添加入口文件, 运行配置

/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; script-src 'self'"
    />
    <meta
      http-equiv="X-Content-Security-Policy"
      content="default-src 'self'; script-src 'self'"
    />
    <title>Hello from Electron renderer!</title>
  </head>
  <body>
    <h1>Hello from Electron renderer!</h1>
    <p>👋</p>
  </body>
</html>

/main.js

// app,它着您应用程序的事件生命周期。
// BrowserWindow,它负责创建和管理应用窗口。
const { app, BrowserWindow } = require('electron')

// 将您的页面加载到新的 BrowserWindow 实例
const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600
  })
  win.loadFile('index.html')
}

// 在 Electron 中,只有在 app 模块的 ready 事件触发后才能创建 BrowserWindows 实例。 您可以通过使用 app.whenReady() API 来监听此事件,并在其成功后调用 createWindow() 方法
app.whenReady().then(() => {
  createWindow()
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow()
    }
  })
})

// 关闭窗口退出应用
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

/package.json

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "Hello World!",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "hgr",
  "license": "ISC",
  "devDependencies": {
    "electron": "^29.1.0"
  }
}

vscode调试

/.vscode/launch.json

{
  "version": "0.2.0",
  "compounds": [
    {
      "name": "Main + renderer",
      "configurations": ["Main", "Renderer"],
      "stopAll": true
    }
  ],
  "configurations": [
    {
      "name": "Renderer",
      "port": 9222,
      "request": "attach",
      "type": "chrome",
      "webRoot": "${workspaceFolder}"
    },
    {
      "name": "Main",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
      "windows": {
        "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
      },
      "args": [".", "--remote-debugging-port=9222"],
      "outputCapture": "std",
      "console": "integratedTerminal"
    }
  ]
}

在vscode侧边栏 运行和调试(ctrl+shift+D), Main+renderer 打断点调试

控制台调试

ctrl + shift + i

运行桌面端

cnpm run start

生命周期

通过检查 Node.js 的 process.platform 变量,您可以针对特定平台运行特定代码。 请注意,Electron 目前只支持三个平台:win32 (Windows), linux (Linux) 和 darwin (macOS)

关闭所有窗口时退出应用 (Windows & Linux)

监听 app 模块的 window-all-closed 事件,并调用 app.quit() 来退出您的应用程序

app.on('window-all-closed', () => {  
if (process.platform !== 'darwin') app.quit()  
})

如果没有窗口打开则打开一个窗口 (macOS)

监听模组的 activate 事件,如果没有任何活动的 BrowserWindow,调用 createWindow() 方法新建一个

因为窗口无法在 ready 事件前创建,你应当在你的应用初始化后仅监听 activate 事件。 要实现这个,仅监听 whenReady() 回调即可

app.whenReady().then(() => {  
createWindow()  
  
app.on('activate', () => {  
if (BrowserWindow.getAllWindows().length === 0) createWindow()  
})  
})

预加载脚本

Electron 的主进程是一个拥有着完全操作系统访问权限的Node.js环境。 除了Electron 模组之外,您也可以访问 Node.js 内置模块 和所有通过 npm 安装的包。 另一方面,出于安全原因,渲染进程默认跑在网页页面上,而并非 Node.js里。

为了将 Electron 的不同类型的进程桥接在一起,我们需要使用被称为预加载的特殊脚本。

新建一个 preload.js 文件。该脚本通过 versions 这一全局变量,将 Electron 的 process.versions 对象暴露给渲染器

/preload.js

const { contextBridge } = require('electron')  
  
contextBridge.exposeInMainWorld('versions', {  
node: () => process.versions.node,  
chrome: () => process.versions.chrome,  
electron: () => process.versions.electron  
// 除函数之外,我们也可以暴露变量  
})

/main.js

const { app, BrowserWindow } = require('electron')
+ const path = require('path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
+    webPreferences: {
+      preload: path.join(__dirname, 'preload.js')
+    }
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {  
  createWindow()  
})

现在渲染器能够全局访问 versions 了,让我们快快将里边的信息显示在窗口中。 这个变量不仅可以通过 window.versions 访问,也可以很简单地使用 versions 来访问。

示例: renderer.js

const information = document.getElementById('info')  
information.innerText = `本应用正在使用 Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), 和 Electron (v${versions.electron()})`

index.html

<!DOCTYPE html>
<html>
  ...
  <body>
    <h1>来自 Electron 渲染器的问好!</h1>
    <p>👋</p>
    <p id="info"></p>
  </body>
  <script src="./renderer.js"></script>
</html>

进程之间通信

从渲染进程直接访问 Node.js 接口,亦或者是从主进程访问 HTML 文档对象模型 (DOM),都是不可能的

使用进程间通信 (IPC)。可以使用 Electron 的 ipcMain 模块和 ipcRenderer 模块来进行进程间通信

/preload.js

+ const { contextBridge, ipcRenderer } = require('electron')  
  
contextBridge.exposeInMainWorld('versions', {  
    node: () => process.versions.node,  
    chrome: () => process.versions.chrome,  
    electron: () => process.versions.electron,  
+    ping: () => ipcRenderer.invoke('ping')  
    // 除函数之外,我们也可以暴露变量  
})

/main.js

+ const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })
  win.loadFile('index.html')
}
app.whenReady().then(() => {
+  ipcMain.handle('ping', () => 'pong')
  createWindow()
})

renderer.js

const func = async () => {
  const response = await window.versions.ping()
  console.log(response) // 打印 'pong'
}

func()

打包应用

cnpm i --save-dev @electron-forge/cli @electron-forge/maker-zip @electron-forge/maker-deb @electron-forge/maker-rpm @electron-forge/maker-squirrel @electron-forge/plugin-auto-unpack-natives

/package.json

//...  
"scripts": {  
    "start": "electron-forge start",  
    "package": "electron-forge package",  
    "make": "electron-forge make"  
},  
//...

代码签名

/forge.config.js

module.exports = {
  packagerConfig: {
    asar: true,
    platform: 'win32',
    osxSign: {},
    // ...
    osxNotarize: {
      tool: 'notarytool',
      appleId: process.env.APPLE_ID,
      appleIdPassword: process.env.APPLE_PASSWORD,
      teamId: process.env.APPLE_TEAM_ID
    }
    // ...
  },
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {},
    },
    {
      name: '@electron-forge/maker-zip',
      platforms: ['win32'],
    },
    {
      name: '@electron-forge/maker-deb',
      config: {},
    },
    {
      name: '@electron-forge/maker-rpm',
      config: {},
    },
  ],
  plugins: [
    {
      name: '@electron-forge/plugin-auto-unpack-natives',
      config: {}
    }
  ]
}

打包命令

cnpm run make

发布和更新

electronjs.p2hp.com/docs/latest…