• 搭建 Vite + Vue3 + TypeScript + Electron 项目


    • 源码参考:mine-desktop,如果以下有些许细节没有表达出来,可以参考此源码。

    方法一、创建一个 Vite 项目

    npm init vite@latest
    
    • 1

    方法二、从零开始

    初始化 package.json

    npm init -y
    
    • 1

    安装依赖

    安装 vue 依赖

    npm i vue vue-router
    
    • 1
    • 安装构建工具
    • 这里使用 Less 作为 css 预编译器
    npm i -D @vitejs/plugin-vue vite less
    
    • 1

    安装 TS 依赖

    npm i -D typescript vue-tsc @types/node
    
    • 1

    安装 Electron 依赖

    • 这里使用 electron-builder 作为打包工具
    npm i -D electron electron-builder
    
    • 1

    安装 Eslint (可选)

    npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser @vitejs/plugin-vue eslint eslint-config-airbnb-base eslint-config-prettier eslint-plugin-import eslint-plugin-prettier eslint-plugin-vue prettier
    
    • 1

    初始化文件

    👀 vite.config.ts
    import { defineConfig, UserConfig } from 'vite'
    import { resolve } from 'path'
    import vue from '@vitejs/plugin-vue'
    
    export const config: UserConfig = {
      base: './',
      plugins: [vue()],
      resolve: {
        // 路径别名
        alias: {
          '@': resolve(__dirname, './src')
        }
      },
      css: {
        // 配置预编译器
        preprocessorOptions: {
          less: {
            javascriptEnabled: true,
            additionalData: `@import '@/styles/variables.less';`
          }
        }
      },
      build: {
        outDir: './dist/resources/vue',
        sourcemap: false
      }
    }
    
    export default defineConfig(config)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    👀 tsconfig.json
    {
      "compilerOptions": {
        "incremental": false,
        "composite": false,
        "target": "esnext",
        "useDefineForClassFields": true,
        "module": "esnext",
        "moduleResolution": "node",
        "strict": true,
        "jsx": "preserve",
        "sourceMap": true,
        "resolveJsonModule": true,
        "isolatedModules": true,
        "esModuleInterop": true,
        "lib": ["esnext", "dom"],
        "types": ["vite/client", "node"],
        "skipLibCheck": true,
        "baseUrl": "./",
        "paths": {
          "@/*": ["./src/*"]
        }
      },
      "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "vite.config.ts", "app/**/*.ts"]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    👀 根目录
    |-- electron-demo --------------------- 项目名称
        |-- index.html -------------------- HTML 页面
        |-- tsconfig.json ----------------- TS 配置
        |-- vite.config.ts ---------------- Vite 配置
        |-- app --------------------------- Electron 主目录
        |   |-- vite.config.ts ------------ 关于 Electron 的 Vite 基础配置
        |   |-- assets -------------------- 资源目录
        |   |   |-- 256x256.ico ----------- 应用图标
        |   |   |-- 256x256.png ----------- 应用图标
        |   |-- main ---------------------- 主程序根目录
        |   |   |-- vite.config.ts -------- 主程序的 Vite 配置
        |   |   |-- src ------------------- 主程序目录
        |   |       |-- main.ts ----------- 主程序入口
        |   |-- preload ------------------- Electron 预加载目录
        |       |-- vite.config.ts -------- 预加载的 Vite 配置
        |       |-- src ------------------- 预加载程序目录
        |           |-- bridge.ts --------- bridge 模块
        |           |-- index.ts ---------- 预加载程序入口
        |-- public ------------------------ 静态资源
        |   |-- favicon.ico --------------- favicon
        |-- src --------------------------- vue 项目
            |-- App.vue ------------------- 页面入口
            |-- env.d.ts ------------------ TS 模板声明
            |-- main.ts ------------------- 入口
            |-- assets -------------------- 资源目录
            |-- components ---------------- 公共组件
            |-- router -------------------- 路由
            |-- styles -------------------- 样式
            |-- views --------------------- 页面
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    👀 main.ts
    import { createApp } from 'vue'
    import Antd from 'ant-design-vue'
    import router from './router'
    import App from './App.vue'
    
    const app = createApp(App)
    
    app.use(router)
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    思路

    Vue 项目

    • 保持原有目录不变,在此基础上加入 Electron 配置。
    • 此软件的界面都使用 Vue 页面,和 Electron 没有任何关系,Electron 只做代码交互。

    Electron 项目

    • 支持 TS:主要通过 vite 来打包 Electron 程序为 lib,从而达到实现开发为 TS 的目的。

    Vue 和 Electron 通信

    Electron 定义

    👀 app/main/src/main.ts
    import { app, BrowserWindow, BrowserWindowConstructorOptions, ipcMain } from 'electron'
    import { resolve } from 'path'
    
    // 初始化程序
    
    /**
     * 创建窗口
     */
    const createWindow = () => {
      const browserWindowOption: BrowserWindowConstructorOptions = {
        titleBarStyle: 'hidden',
        width: 1000,
        height: 600,
        webPreferences: {
          nodeIntegration: true,
          enableWebSQL: false,
          preload: resolve(__dirname, '../preload/index.cjs') // 预加载程序,此为 `preload/src/index.ts` 使用 Vite 打包之后的 lib 文件
        }
      }
      const window = new BrowserWindow(browserWindowOption)
    
      window.setMenuBarVisibility(false)
    
      let pageUrl: string // 页面路径
      // 开发
      if (import.meta.env.MODE === 'development') {
        pageUrl = 'http://localhost:3400'
        window.webContents.openDevTools()
      } else {
        pageUrl = new URL('../../resources/vue/index.html', `file://${__dirname}`).toString() // 打包
      }
      window.loadURL(pageUrl)
      // 定义通信事件, quit 为自定义名称
      ipcMain.handle('quit', () => {
        app.quit()
      })
    }
    
    app.whenReady().then(() => {
      createWindow()
      app.on('activate', function () {
        !BrowserWindow.getAllWindows().length && createWindow()
      })
    })
    
    app.on('window-all-closed', () => {
      process.platform !== 'darwin' && app.quit()
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 定义通信事件
    // 定义通信事件, quit 为自定义名称,注意在 Vue 里使用的时候保持一致
    ipcMain.handle('quit', () => {
      app.quit()
    })
    
    • 1
    • 2
    • 3
    • 4
    👀 app/preload/src/bridge.ts
    import { contextBridge, ipcRenderer } from 'electron'
    // electron 是为 Vue 注入全局变量 electron, ipcRenderer 为注入的模块
    contextBridge.exposeInMainWorld('electron', {
      ipcRenderer
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Vue 使用

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Electron 打包配置

    👀 electron-builder.json 或 package.json 的 build
    {
      "appId": "mine.desktop.app",
      "electronVersion": "19.0.4",
      "copyright": "Copyright (c) 2022-present biaov",
      "asar": true,
      "directories": {
        "output": "./dist/package"
      },
      "win": {
        "icon": "./app/assets/256x256.ico",
        "requestedExecutionLevel": "highestAvailable",
        "target": [
          {
            "target": "nsis",
            "arch": ["x64"]
          }
        ]
      },
      "nsis": {
        "allowElevation": true,
        "allowToChangeInstallationDirectory": true,
        "artifactName": "mine-desktop.${ext}",
        "createDesktopShortcut": true,
        "createStartMenuShortcut": true,
        "installerIcon": "./app/assets/256x256.ico",
        "uninstallerIcon": "./app/assets/256x256.ico",
        "installerHeaderIcon": "./app/assets/256x256.ico",
        "uninstallDisplayName": "uninstall",
        "oneClick": false,
        "shortcutName": "mine-desktop",
        "useZip": true,
        "deleteAppDataOnUninstall": false,
        "displayLanguageSelector": false,
        "perMachine": true
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    {
      "name": "electron-demo",
      "version": "1.0.0",
      "scripts": {},
      "build": {
        "appId": "mine.desktop.app",
        ...同上
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    总结

    • 总体上来说,如果你不用 Electron 自带的界面,那么除了交互,其它的和 Vue 项目没有区别。
    • 源码参考:mine-desktop,如果以上有些许细节没有表达出来,可以参考此源码。
  • 相关阅读:
    极智AI | 三谈昇腾 auto tune
    在线汽车交易平台数字化转型案例—BI工具是关键!
    Git 常用命令
    HashMap 源码分析
    安卓金钱过滤器(保留两位小数,保证小数点前面保留几位数)
    C语言 字符函数汇总,模拟实现各字符函数(炒鸡详细)
    FreeRTOS基础(如何学好FreeRTOS?)
    基于鸽群算法优化最小二乘支持向量机lssvm实现预测附matlab代码
    Jenkins设置root权限(13)
    Python的基础算法题
  • 原文地址:https://blog.csdn.net/biao_feng/article/details/125887906