vue+vite迁移electron-vite

前言

最近博主正在尝试将之前开发的vue项目迁移到electron-vite,提供desktop端。写下该博客记录一下过程。同时希望能帮助到有同样需要的人。

Electron-vite

Electron-Vite 是一个基于 Vite 的构建工具,专为 Electron 应用开发设计,旨在提供高效的开发体验和优化的生产构建。它将 Vite 的快速开发能力与 Electron 的桌面应用框架结合,简化了 Electron 项目的配置和构建流程。

官方文档:

cn.electron-vite.orgIntroductionhttps://cn.electron-vite.org/guide/introduction

安装必要依赖

npm install electron electron-vite -D

由于npm下载速度缓慢。可以考虑使用代理或设置国内镜像来加速下载

# 设置国内镜像
$env:ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/"

修改目录结构

Electron-vite项目开发约定俗成的开发目录如下

.
├──src
│  ├──main
│  │  ├──index.ts
│  │  └──...
│  ├──preload
│  │  ├──index.ts
│  │  └──...
│  └──renderer    # with vue, react, etc.
│     ├──src
│     ├──index.html
│     └──...
├──electron.vite.config.ts
├──package.json
└──...

因此需要将原来的项目目录结构进行修改,将原本的src目录迁移至src/renderer目录下。原来的App.vue,main.js,index.html等文件也需要移动至src/renderer目录下。

迁移文件时,记得确认index.html文件中指向main.js的路径是否正确

<!doctype html>
<html lang="en">
  <head>
    ....
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="./main.js"></script>
  </body>
</html>

此外还需要添加electron.vite.config.js文件,用于配置electron-vite。

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

export default defineConfig({
  main: {
    build: {
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'src/main/index.js')
        }
      }
    }
  },
  preload: {
    build: {
      rollupOptions: {
        input: {
          preload: resolve(__dirname, 'src/preload/index.js')
        }
      }
    }
  },
  renderer: {
    root: resolve(__dirname, 'src/renderer'),
    resolve: {
        alias: {
            '@': resolve(__dirname,'src/renderer') // 设置别名
        }
    },
    plugins: [vue()],
    build: {
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'src/renderer/index.html')
        }
      }
    }
  }
})

主进程文件 src/main/index.js

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

const iconPath = path.join(__dirname, '../../resources/icon.png');

const createWindow = () => {
  const win = new BrowserWindow({
    width: 1200,
    height: 800,
    webPreferences: {
      preload: path.join(__dirname, '../preload/index.js')
    },
    icon: iconPath // 设置图标
  })

  // 开发环境加载 Vite 开发服务器
  if (process.env.NODE_ENV === 'development') {
    win.loadURL('http://localhost:5173') // 端口与 Vite 开发服务器一致
    win.webContents.openDevTools()
  } else {
    // 生产环境加载打包后的文件
    win.loadFile(path.join(__dirname, '../../out/renderer/index.html'))
  }
}

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

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

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

通常将静态资源放在resources目录下,或者保持原来的public目录。

.
├──resources
├──src
├──electron.vite.config.ts
├──package.json
└──...

预加载脚本 src/preload/index.js

import { contextBridge } from 'electron'

// 安全暴露 API 给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
  // 示例方法
  platform: process.platform
})

更新package.json文件

{
  "name": "your-app",
  "version": "1.0.0",
  "main": "./out/main/index.js", // 指向打包后的主进程
  "description": "",
  "author": "your-name",
  "scripts": {
    "dev": "electron-vite dev", // 开发模式
    "build": "electron-vite build", // 生产构建
    "preview": "electron-vite preview" // 预览生产包
  }
}

补充说明:

  • electron-vite 运行时会默认生成一个out目录,通常含有mainpreload目录,存放主进程与预加载脚本。运行build后还会产生renderer目录。用于存放打包后的渲染脚本(相当于原本的dist目录)。
  • "description","author"等字段是后面打包成app端所必须的字段

目录结构大致如下

.
├──out
├──resources
├──src
├──electron.vite.config.ts
├──package.json
└──...

至此,整个迁移过程结束,可以运行npm run dev启动项目,查看是否迁移成功

Electron-builder

正如前言所说,本次迁移是为了能够创建桌面端应用,因此还需要将electron-vite项目打包。但是electron-vite本身并不能提供安装包形式的打包。其本身的打包只能将项目打包为静态文件。

因此还需要借助额外的打包工具来完成打包。常见的工具有electron-builder,electron-forge等。本文采用electron-builder来进行打包。

安装依赖

npm install electron-builder --save-dev

修改package.json文件

{
  "name": "your-app",
  "version": "1.0.0",
  "description": "Your app description",
  "main": "main.js",
  "author": "Your Name <your@email.com>",
  "scripts": {
    "dev": "electron-vite dev",
    "build": "electron-vite build",
    "preview": "electron-vite preview",
    "pack": "electron-builder --dir",
    "build:app": "electron-vite build && electron-builder"
  },
  "build": {
    "appId": "com.example.yourapp",
    "productName": "Your App",
    "copyright": "Copyright © 2023 ${author}",
    "directories": {
      "output": "dist"
    },
    "files": [
      "**/*",
      "!node_modules/{@electron-forge,electron-forge*}"
    ],
    "asar": true,
    "win": {
      "target": ["nsis", "portable"],
      "icon": "build/icon.ico"
    },
    "mac": {
      "category": "public.app-category.utilities",
      "target": ["dmg", "zip"],
      "icon": "build/icon.icns"
    },
    "linux": {
      "target": ["AppImage", "deb"],
      "icon": "build/icon.png"
    }
  }
}

接下来可以运行npm run pack来进行打包测试,该命令不会生成安装包。

或者直接运行npm run build:app进行打包。

打包过程中可能遇到的问题

在打包过程中,可能会遇到一些问题。例如无法构建链接或无法访问GitHub等。

无法构建链接

错误信息:ERROR: Cannot create symbolic link 该问题可以通过禁用符号链接解决。在package.json文件的build字段中做如下修改

"build": {
  "win": {
    "requestedExecutionLevel": "asInvoker",
    "asar": true
  }
}

无法访问GitHub

运行electron-builder时,主要是需要从Github中下载nsiswinCodesign等模块。可能由于网络原因导致无法访问Github,导致下载失败。

错误信息:

 Get "https://github.com/electron-userland/electron-builder-binaries/releases/download/winCodeSign-2.6.0/winCodeSign-2.6.0.7z": 
 read tcp 192.168.1.13:51887->20.205.243.166:443: wsarecv: 
 A connection attempt failed because the connected party did not properly respond after a period of time, 
 or established connection failed because connected host has failed to respond.

该问题可以通过设置网络代理来解决。也可以手动下载需要的模块,然后放置到指定目录C:\user\AppData\Local\electron-builder\Cache中即可。目录结构如下

├──nsis
    ├──nsis-3.0.4.1
    ├──nsis-resources-3.4.1
├──winCodeSign
    ├──winCodeSign-2.6.0

需要注意下载的版本要与打包需要的版本一致。具体可在打包报错时查看。以及下载链接也可以在打包错误信息中获取。例如上面错误信息中的

"https://github.com/electron-userland/electron-builder-binaries/releases/download/winCodeSign-2.6.0/winCodeSign-2.6.0.7z"

设置代理

npm config set proxy http://your-proxy:port
npm config set https-proxy http://your-proxy:port