diff --git a/.gitignore b/.gitignore
index aa4b2f5..d9cd1a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,77 +1,20 @@
-# ---> Node
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+pnpm-debug.log*
lerna-debug.log*
-.pnpm-debug.log*
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+node_modules
+dist
+dist-ssr
+dist-electron
+release
+*.local
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directories
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-web_modules/
-
-# TypeScript cache
-*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional stylelint cache
-.stylelintcache
-
-# Microbundle cache
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
# dotenv environment variable files
.env
@@ -80,64 +23,19 @@ web_modules/
.env.production.local
.env.local
-# parcel-bundler cache (https://parceljs.org/)
-.cache
-.parcel-cache
-
-# Next.js build output
-.next
-out
-
-# Nuxt.js build / generate output
-.nuxt
-dist
-
-# Gatsby files
-.cache/
-# Comment in the public line in if your project uses Gatsby and not Next.js
-# https://nextjs.org/blog/next-9-1#public-directory-support
-# public
-
-# vuepress build output
-.vuepress/dist
-
-# vuepress v2.x temp and cache directory
-.temp
-.cache
-
-# Docusaurus cache and generated files
-.docusaurus
-
-# Serverless directories
-.serverless/
-
-# FuseBox cache
-.fusebox/
-
-# DynamoDB Local files
-.dynamodb/
-
-# TernJS port file
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-.vscode-test
-
-# yarn v2
-.yarn/cache
-.yarn/unplugged
-.yarn/build-state.yml
-.yarn/install-state.gz
-.pnp.*
-
-# ---> Vue
-# gitignore template for Vue.js projects
-#
-# Recommended template: Node.gitignore
-
-# TODO: where does this rule come from?
-docs/_book
-
-# TODO: where does this rule come from?
-test/
+# Editor directories and files
+.vscode
+.vscode/.debug.env
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+# lockfile
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
+.history
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..db6dbaa
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,33 @@
+## 2022-10-03
+
+[v2.1.0](https://github.com/electron-vite/electron-vite-vue/pull/267)
+
+- `vite-electron-plugin` is Fast, and WYSIWYG. π±
+- last-commit: db2e830 v2.1.0: use `vite-electron-plugin` instead `vite-plugin-electron`
+
+## 2022-06-04
+
+[v2.0.0](https://github.com/electron-vite/electron-vite-vue/pull/156)
+
+- π Based on the `vue-ts` template created by `npm create vite`, integrate `vite-plugin-electron`
+- β‘οΈ More simplify, is in line with Vite project structure
+- last-commit: a15028a (HEAD -> main) feat: hoist `process.env`
+
+## 2022-01-30
+
+[v1.0.0](https://github.com/electron-vite/electron-vite-vue/releases/tag/v1.0.0)
+
+- β‘οΈ MainγRendererγpreload, all built with vite
+
+## 2022-01-27
+- Refactor the scripts part.
+- Remove `configs` directory.
+
+## 2021-11-11
+- Refactor the project. Use vite.config.ts build `Main-process`, `Preload-script` and `Renderer-process` alternative rollup.
+- Scenic `Vue>=3.2.13`, `@vue/compiler-sfc` is no longer necessary.
+- If you prefer Rollup, Use rollup branch.
+
+```bash
+Error: @vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc to be present in the dependency tree.
+```
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..22edc0e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 θι沑ε·
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 90cda29..359d4a7 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,71 @@
-# monitor
+# electron-vite-vue
+π₯³ Really simple `Electron` + `Vue` + `Vite` boilerplate.
+
+
+
+
+
+
+[![GitHub Build](https://github.com/electron-vite/electron-vite-vue/actions/workflows/build.yml/badge.svg)](https://github.com/electron-vite/electron-vite-vue/actions/workflows/build.yml)
+[![GitHub Discord](https://img.shields.io/badge/chat-discord-blue?logo=discord)](https://discord.gg/sRqjYpEAUK)
+
+## Features
+
+π¦ Out of the box
+π― Based on the official [template-vue-ts](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-vue-ts), less invasive
+π± Extensible, really simple directory structure
+πͺ Support using Node.js API in Electron-Renderer
+π© Support C/C++ native addons
+π₯ It's easy to implement multiple windows
+
+## Quick Start
+
+```sh
+npm create electron-vite
+```
+
+
+
+![electron-vite-vue.gif](/public/electron-vite-vue.gif)
+
+## Debug
+
+![electron-vite-react-debug.gif](https://github.com/electron-vite/electron-vite-react/blob/main/public/electron-vite-react-debug.gif?raw=true)
+
+## Directory
+
+```diff
++ βββ¬ electron
++ β βββ¬ main
++ β β βββ index.ts entry of Electron-Main
++ β βββ¬ preload
++ β βββ index.ts entry of Preload-Scripts
+ βββ¬ src
+ β βββ main.ts entry of Electron-Renderer
+ βββ index.html
+ βββ package.json
+ βββ vite.config.ts
+```
+
+## Be aware
+
+π¨ By default, this template integrates Node.js in the Renderer process. If you don't need it, you just remove the option below. [Because it will modify the default config of Vite](https://github.com/electron-vite/vite-plugin-electron-renderer#config-presets-opinionated).
+
+```diff
+# vite.config.ts
+
+export default {
+ plugins: [
+- // Use Node.js API in the Renderer-process
+- renderer({
+- nodeIntegration: true,
+- }),
+ ],
+}
+```
+
+## FAQ
+
+- [dependencies vs devDependencies](https://github.com/electron-vite/vite-plugin-electron-renderer#dependencies-vs-devdependencies)
+- [C/C++ addons, Node.js modules - Pre-Bundling](https://github.com/electron-vite/vite-plugin-electron-renderer#dependency-pre-bundling)
diff --git a/electron-builder.json5 b/electron-builder.json5
new file mode 100644
index 0000000..cc8c811
--- /dev/null
+++ b/electron-builder.json5
@@ -0,0 +1,38 @@
+/**
+ * @see https://www.electron.build/configuration/configuration
+ */
+{
+ "appId": "YourAppID",
+ "asar": true,
+ "icon": "public/favicon.ico",
+ "directories": {
+ "output": "release/${version}"
+ },
+ "files": [
+ "dist-electron",
+ "dist"
+ ],
+ "mac": {
+ "artifactName": "${productName}_${version}.${ext}",
+ "target": [
+ "dmg"
+ ]
+ },
+ "win": {
+ "target": [
+ {
+ "target": "nsis",
+ "arch": [
+ "x64"
+ ]
+ }
+ ],
+ "artifactName": "${productName}_${version}.${ext}"
+ },
+ "nsis": {
+ "oneClick": false,
+ "perMachine": false,
+ "allowToChangeInstallationDirectory": true,
+ "deleteAppDataOnUninstall": false
+ }
+}
diff --git a/electron/electron-env.d.ts b/electron/electron-env.d.ts
new file mode 100644
index 0000000..d02e86c
--- /dev/null
+++ b/electron/electron-env.d.ts
@@ -0,0 +1,11 @@
+///
+
+declare namespace NodeJS {
+ interface ProcessEnv {
+ VSCODE_DEBUG?: 'true'
+ DIST_ELECTRON: string
+ DIST: string
+ /** /dist/ or /public/ */
+ PUBLIC: string
+ }
+}
diff --git a/electron/main/index.ts b/electron/main/index.ts
new file mode 100644
index 0000000..8862366
--- /dev/null
+++ b/electron/main/index.ts
@@ -0,0 +1,127 @@
+import { app, BrowserWindow, shell, ipcMain } from 'electron'
+import { release } from 'node:os'
+import { join } from 'node:path'
+
+import { SimconnectClient } from '../simconnect/Client'
+
+// The built directory structure
+//
+// βββ¬ dist-electron
+// β βββ¬ main
+// β β βββ index.js > Electron-Main
+// β βββ¬ preload
+// β βββ index.js > Preload-Scripts
+// βββ¬ dist
+// β βββ index.html > Electron-Renderer
+//
+process.env.DIST_ELECTRON = join(__dirname, '..')
+process.env.DIST = join(process.env.DIST_ELECTRON, '../dist')
+process.env.PUBLIC = process.env.VITE_DEV_SERVER_URL
+ ? join(process.env.DIST_ELECTRON, '../public')
+ : process.env.DIST
+
+// Disable GPU Acceleration for Windows 7
+if (release().startsWith('6.1')) app.disableHardwareAcceleration()
+
+// Set application name for Windows 10+ notifications
+if (process.platform === 'win32') app.setAppUserModelId(app.getName())
+
+if (!app.requestSingleInstanceLock()) {
+ app.quit()
+ process.exit(0)
+}
+
+// Remove electron security warnings
+// This warning only shows in development mode
+// Read more on https://www.electronjs.org/docs/latest/tutorial/security
+// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
+
+let win: BrowserWindow | null = null
+// Here, you can also use other preload
+const preload = join(__dirname, '../preload/index.js')
+const url = process.env.VITE_DEV_SERVER_URL
+const indexHtml = join(process.env.DIST, 'index.html')
+
+const client: SimconnectClient = new SimconnectClient();
+
+async function createWindow() {
+ win = new BrowserWindow({
+ title: 'Main window',
+ icon: join(process.env.PUBLIC, 'favicon.ico'),
+ webPreferences: {
+ preload,
+ // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
+ // Consider using contextBridge.exposeInMainWorld
+ // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
+ nodeIntegration: true,
+ contextIsolation: false,
+ },
+ })
+
+ if (process.env.VITE_DEV_SERVER_URL) { // electron-vite-vue#298
+ win.loadURL(url)
+ // Open devTool if the app is not packaged
+ win.webContents.openDevTools()
+ } else {
+ win.loadFile(indexHtml)
+ }
+
+ // Test actively push message to the Electron-Renderer
+ win.webContents.on('did-finish-load', () => {
+ win?.webContents.send('main-process-message', new Date().toLocaleString());
+
+
+ try {
+ client.open(win);
+ } catch(err) {
+ console.log(err);
+ }
+ })
+
+ // Make all links open with the browser, not with the application
+ win.webContents.setWindowOpenHandler(({ url }) => {
+ if (url.startsWith('https:')) shell.openExternal(url)
+ return { action: 'deny' }
+ })
+}
+
+app.whenReady().then(createWindow)
+
+app.on('window-all-closed', () => {
+ win = null
+ if (process.platform !== 'darwin') app.quit()
+})
+
+app.on('second-instance', () => {
+ if (win) {
+ // Focus on the main window if the user tried to open another
+ if (win.isMinimized()) win.restore()
+ win.focus()
+ }
+})
+
+app.on('activate', () => {
+ const allWindows = BrowserWindow.getAllWindows()
+ if (allWindows.length) {
+ allWindows[0].focus()
+ } else {
+ createWindow()
+ }
+})
+
+// New window example arg: new windows url
+ipcMain.handle('open-win', (_, arg) => {
+ const childWindow = new BrowserWindow({
+ webPreferences: {
+ preload,
+ nodeIntegration: true,
+ contextIsolation: false,
+ },
+ })
+
+ if (process.env.VITE_DEV_SERVER_URL) {
+ childWindow.loadURL(`${url}#${arg}`)
+ } else {
+ childWindow.loadFile(indexHtml, { hash: arg })
+ }
+})
diff --git a/electron/preload/index.ts b/electron/preload/index.ts
new file mode 100644
index 0000000..ebf1276
--- /dev/null
+++ b/electron/preload/index.ts
@@ -0,0 +1,92 @@
+function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
+ return new Promise((resolve) => {
+ if (condition.includes(document.readyState)) {
+ resolve(true)
+ } else {
+ document.addEventListener('readystatechange', () => {
+ if (condition.includes(document.readyState)) {
+ resolve(true)
+ }
+ })
+ }
+ })
+}
+
+const safeDOM = {
+ append(parent: HTMLElement, child: HTMLElement) {
+ if (!Array.from(parent.children).find(e => e === child)) {
+ return parent.appendChild(child)
+ }
+ },
+ remove(parent: HTMLElement, child: HTMLElement) {
+ if (Array.from(parent.children).find(e => e === child)) {
+ return parent.removeChild(child)
+ }
+ },
+}
+
+/**
+ * https://tobiasahlin.com/spinkit
+ * https://connoratherton.com/loaders
+ * https://projects.lukehaas.me/css-loaders
+ * https://matejkustec.github.io/SpinThatShit
+ */
+function useLoading() {
+ const className = `loaders-css__square-spin`
+ const styleContent = `
+@keyframes square-spin {
+ 25% { transform: perspective(100px) rotateX(180deg) rotateY(0); }
+ 50% { transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
+ 75% { transform: perspective(100px) rotateX(0) rotateY(180deg); }
+ 100% { transform: perspective(100px) rotateX(0) rotateY(0); }
+}
+.${className} > div {
+ animation-fill-mode: both;
+ width: 50px;
+ height: 50px;
+ background: #fff;
+ animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
+}
+.app-loading-wrap {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #282c34;
+ z-index: 9;
+}
+ `
+ const oStyle = document.createElement('style')
+ const oDiv = document.createElement('div')
+
+ oStyle.id = 'app-loading-style'
+ oStyle.innerHTML = styleContent
+ oDiv.className = 'app-loading-wrap'
+ oDiv.innerHTML = `
`
+
+ return {
+ appendLoading() {
+ safeDOM.append(document.head, oStyle)
+ safeDOM.append(document.body, oDiv)
+ },
+ removeLoading() {
+ safeDOM.remove(document.head, oStyle)
+ safeDOM.remove(document.body, oDiv)
+ },
+ }
+}
+
+// ----------------------------------------------------------------------
+
+const { appendLoading, removeLoading } = useLoading()
+domReady().then(appendLoading)
+
+window.onmessage = (ev) => {
+ ev.data.payload === 'removeLoading' && removeLoading()
+}
+
+setTimeout(removeLoading, 4999)
diff --git a/electron/simconnect/Client.ts b/electron/simconnect/Client.ts
new file mode 100644
index 0000000..dd09801
--- /dev/null
+++ b/electron/simconnect/Client.ts
@@ -0,0 +1,141 @@
+import { BrowserWindow } from 'electron';
+import {
+ open,
+ Protocol,
+ SimConnectDataType,
+ SimConnectPeriod,
+ SimConnectConstants,
+ readLatLonAlt,
+ RecvSimObjectData
+} from 'node-simconnect';
+import { DataDefiniion } from './DataDefinition';
+import { DefinitionID, EventID, RequestID } from './enums';
+
+export class SimconnectClient {
+ private requestsMap: Map;
+ private isPaused: Boolean;
+ private onGround: Boolean;
+ private onRunway: Boolean;
+ private window: BrowserWindow;
+
+ constructor() {
+ this.requestsMap = new Map();
+ this.isPaused = true;
+ this.onGround = true;
+ this.onRunway = false;
+
+ }
+
+ async open(win: BrowserWindow) {
+ const { recvOpen, handle } = await open('My SimConnect client', Protocol.KittyHawk);
+ console.log('Connected to', recvOpen);
+ this.subscribeToSystemEvent(handle);
+ this.addDataDefinitions(handle);
+ this.window = win;
+ handle.on('simObjectData', this.objectDataHandler.bind(this));
+
+ }
+
+ objectDataHandler(objectData: RecvSimObjectData) {
+ const { requestID, data } = objectData;
+ if (this.requestsMap.has(requestID)) {
+ const fn: Function = this.requestsMap.get(requestID);
+ fn(data, this.window);
+ }
+ }
+
+ subscribeToSystemEvent(handle) {
+ handle.subscribeToSystemEvent(EventID.PAUSE, 'Pause');
+
+ handle.on('event', function(recvEvent) {
+ switch (recvEvent.clientEventId) {
+ case EventID.PAUSE:
+ console.log(recvEvent.data === 1 ? 'Sim paused' : 'Sim unpaused');
+ this.isPaused = recvEvent.data === 1;
+ break;
+ }
+ }.bind(this));
+ }
+
+ addDataDefinitions(handle) {
+ const onGroundDef = new DataDefiniion(
+ DefinitionID.ON_GROUND,
+ RequestID.ON_GROUND,
+ SimConnectPeriod.SECOND,
+ data => {
+ const onGround = data.readInt32() === 1;
+ console.log('On Groud :>> ', onGround);
+ this.onGround = onGround;
+ }
+ );
+ const onRunwayDef = new DataDefiniion(
+ DefinitionID.ON_RUNWAY,
+ RequestID.ON_RUNWAY,
+ SimConnectPeriod.SECOND,
+ (data, window) => {
+ const isOnRunway = data.readInt32() === 1;
+ console.log('On Runway :>> ', isOnRunway);
+ this.onRunway = isOnRunway;
+ window.send('data_on_runway', this.onRunway);
+ }
+ );
+ const liveDef = new DataDefiniion(
+ DefinitionID.LIVE_DATA,
+ RequestID.LIVE_DATA,
+ SimConnectPeriod.SECOND,
+ data => {
+ console.log('this.isPaused :>> ', this.isPaused);
+ if (!this.isPaused) {
+ const timestamp = new Date().getTime();
+ const { latitude, longitude, altitude } = readLatLonAlt(data);
+ const airspeed = data.readInt32();
+ const verticalSpeed = data.readInt32();
+ const heading = data.readInt32();
+ console.log("position", `${latitude} ${longitude} ${altitude}`,
+ "airspeed", airspeed,
+ "vertical speed", verticalSpeed,
+ "heading", heading,
+ // "landing lights", recvSimObjectData.data.readInt32(),
+ // "logo lights", recvSimObjectData.data.readInt32(),
+ // "taxi lights", recvSimObjectData.data.readInt32(),
+ // "wing lights", recvSimObjectData.data.readInt32(),
+ // "nav lights", recvSimObjectData.data.readInt32(),
+ // "beacon lights", recvSimObjectData.data.readInt32()
+ );
+ }
+ }
+ );
+ const aircraftDef = new DataDefiniion(
+ DefinitionID.AIRCRAFT_DATA,
+ RequestID.AIRCRAFT_DATA,
+ SimConnectPeriod.ONCE,
+ data => {
+ console.log('===================================');
+ console.log(`Type: "${data.readStringV()}"`);
+ console.log(`Title: "${data.readStringV()}"`);
+ console.log(`ATC ID: "${data.readString32()}"`);
+ console.log('===================================');
+ }
+ );
+ onGroundDef.add(['SIM ON GROUND', 'bool', SimConnectDataType.INT32, 0, SimConnectConstants.UNUSED]);
+ onRunwayDef.add(['ON ANY RUNWAY', 'bool', SimConnectDataType.INT32, 0, SimConnectConstants.UNUSED])
+ liveDef.add(['STRUCT LATLONALT', null, SimConnectDataType.LATLONALT]);
+ liveDef.add(['AIRSPEED INDICATED', 'knots', SimConnectDataType.INT32]);
+ liveDef.add(['VERTICAL SPEED', 'Feet per second', SimConnectDataType.INT32]);
+ liveDef.add(['PLANE HEADING DEGREES TRUE', 'Degrees', SimConnectDataType.INT32]);
+ liveDef.add(['LIGHT LANDING', 'bool', SimConnectDataType.INT32]);
+ liveDef.add(['LIGHT LOGO', 'bool', SimConnectDataType.INT32]);
+ liveDef.add(['LIGHT TAXI', 'bool', SimConnectDataType.INT32]);
+ liveDef.add(['LIGHT WING', 'bool', SimConnectDataType.INT32]);
+ liveDef.add(['LIGHT NAV', 'bool', SimConnectDataType.INT32]);
+ liveDef.add(['LIGHT BEACON', 'bool', SimConnectDataType.INT32]);
+ aircraftDef.add(['CATEGORY', null, SimConnectDataType.STRINGV, 0, SimConnectConstants.UNUSED]);
+ aircraftDef.add(['TITLE', null, SimConnectDataType.STRINGV, 0, SimConnectConstants.UNUSED]);
+ aircraftDef.add(['ATC ID', null, SimConnectDataType.STRING32, 0, SimConnectConstants.UNUSED]);
+ onGroundDef.build(handle, this.requestsMap);
+ onRunwayDef.build(handle, this.requestsMap);
+ liveDef.build(handle, this.requestsMap);
+ // aircraftDef.build(handle, this.requestsMap);
+ }
+
+}
\ No newline at end of file
diff --git a/electron/simconnect/DataDefinition.ts b/electron/simconnect/DataDefinition.ts
new file mode 100644
index 0000000..1863e02
--- /dev/null
+++ b/electron/simconnect/DataDefinition.ts
@@ -0,0 +1,29 @@
+import { SimConnectConstants } from 'node-simconnect';
+
+export class DataDefiniion {
+ private definitions: Array = [];
+ private id: number;
+ private requestId: number;
+ private period: number;
+ private handler: Function;
+
+ constructor(id, requestId, period, handler) {
+ this.id = id;
+ this.requestId = requestId;
+ this.handler = handler;
+ this.period = period;
+ }
+
+ add(definition :Array): void {
+ this.definitions.push(definition);
+ }
+
+ build(handle, requestsMap: Map) {
+ this.definitions.forEach(definition => {
+ handle.addToDataDefinition(this.id, ...definition);
+ });
+ requestsMap.set(this.requestId, this.handler);
+ handle.requestDataOnSimObject(this.requestId, this.id, SimConnectConstants.OBJECT_ID_USER, this.period);
+ }
+
+}
\ No newline at end of file
diff --git a/electron/simconnect/enums.ts b/electron/simconnect/enums.ts
new file mode 100644
index 0000000..35b3b1c
--- /dev/null
+++ b/electron/simconnect/enums.ts
@@ -0,0 +1,18 @@
+
+export enum EventID {
+ PAUSE,
+};
+
+export enum DefinitionID {
+ LIVE_DATA,
+ AIRCRAFT_DATA,
+ ON_GROUND,
+ ON_RUNWAY,
+};
+
+export enum RequestID {
+ LIVE_DATA,
+ AIRCRAFT_DATA,
+ ON_GROUND,
+ ON_RUNWAY,
+};
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..2c2325b
--- /dev/null
+++ b/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Electron + Vite + Vue
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..355472a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "electron-vue-vite",
+ "version": "2.0.0",
+ "main": "dist-electron/main/index.js",
+ "description": "Really simple Electron + Vue + Vite boilerplate.",
+ "author": "θιζ²‘ε· <308487730@qq.com>",
+ "license": "MIT",
+ "private": true,
+ "keywords": [
+ "electron",
+ "rollup",
+ "vite",
+ "vue3",
+ "vue"
+ ],
+ "debug": {
+ "env": {
+ "VITE_DEV_SERVER_URL": "http://127.0.0.1:3344/"
+ }
+ },
+ "scripts": {
+ "dev": "vite",
+ "build": "vue-tsc --noEmit && vite build && electron-builder",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^4.0.0",
+ "electron": "^22.0.3",
+ "electron-builder": "^23.6.0",
+ "typescript": "^4.9.4",
+ "vite": "^4.0.4",
+ "vite-plugin-electron": "^0.11.1",
+ "vite-plugin-electron-renderer": "^0.11.4",
+ "vue": "^3.2.45",
+ "vue-tsc": "^1.0.24"
+ },
+ "dependencies": {
+ "node-simconnect": "^3.3.0"
+ }
+}
diff --git a/public/electron-vite-vue.gif b/public/electron-vite-vue.gif
new file mode 100644
index 0000000..66a14af
Binary files /dev/null and b/public/electron-vite-vue.gif differ
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..843ea24
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/node.svg b/public/node.svg
new file mode 100644
index 0000000..38d4eaa
--- /dev/null
+++ b/public/node.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/vite.svg b/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..d679871
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ Place static files into the
/public
folder
+
+
+
+
+
diff --git a/src/assets/electron.svg b/src/assets/electron.svg
new file mode 100644
index 0000000..1c5cccb
--- /dev/null
+++ b/src/assets/electron.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/vue.svg b/src/assets/vue.svg
new file mode 100644
index 0000000..770e9d3
--- /dev/null
+++ b/src/assets/vue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue
new file mode 100644
index 0000000..5230910
--- /dev/null
+++ b/src/components/HelloWorld.vue
@@ -0,0 +1,38 @@
+
+
+
+ {{ msg }}
+
+
+
+
+ Edit
+ components/HelloWorld.vue
to test HMR
+
+
+
+
+ Check out
+ create-vue, the official Vue + Vite starter
+
+
+ Install
+ Volar
+ in your IDE for a better DX
+
+ Click on the Vite and Vue logos to learn more
+
+
+
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..e864d88
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,10 @@
+import { createApp } from 'vue'
+import "./style.css"
+import App from './App.vue'
+import './samples/node-api'
+
+createApp(App)
+ .mount('#app')
+ .$nextTick(() => {
+ postMessage({ payload: 'removeLoading' }, '*')
+ })
diff --git a/src/samples/node-api.ts b/src/samples/node-api.ts
new file mode 100644
index 0000000..b1d9a83
--- /dev/null
+++ b/src/samples/node-api.ts
@@ -0,0 +1,18 @@
+import { lstat } from 'node:fs/promises'
+import { cwd } from 'node:process'
+import { ipcRenderer } from 'electron'
+
+ipcRenderer.on('main-process-message', (_event, ...args) => {
+ console.log('[Receive Main-process message]:', ...args)
+})
+
+ipcRenderer.on('data_on_runway', (_event, ...args) => {
+ console.log('[Receive data_on_runway message]:', ...args)
+ console.log('document :>> ', document);
+})
+
+lstat(cwd()).then(stats => {
+ console.log('[fs.lstat]', stats)
+}).catch(err => {
+ console.error(err)
+})
diff --git a/src/style.css b/src/style.css
new file mode 100644
index 0000000..64aafe8
--- /dev/null
+++ b/src/style.css
@@ -0,0 +1,90 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+code {
+ background-color: #1a1a1a;
+ padding: 2px 4px;
+ margin: 0 4px;
+ border-radius: 4px;
+}
+
+.card {
+ padding: 2em;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+ code {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..323c78a
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,7 @@
+///
+
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..6d0f5ee
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "strict": true,
+ "jsx": "preserve",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "lib": ["ESNext", "DOM"],
+ "skipLibCheck": true,
+ "noEmit": true
+ },
+ "include": ["src"],
+ "references": [
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 0000000..ed1b586
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "resolveJsonModule": true,
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["vite.config.ts", "package.json", "electron"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..55e26c6
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,74 @@
+import { rmSync } from 'node:fs'
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import electron from 'vite-plugin-electron'
+import renderer from 'vite-plugin-electron-renderer'
+import pkg from './package.json'
+
+// https://vitejs.dev/config/
+export default defineConfig(({ command }) => {
+ rmSync('dist-electron', { recursive: true, force: true })
+
+ const isServe = command === 'serve'
+ const isBuild = command === 'build'
+ const sourcemap = isServe || !!process.env.VSCODE_DEBUG
+
+ return {
+ plugins: [
+ vue(),
+ electron([
+ {
+ // Main-Process entry file of the Electron App.
+ entry: 'electron/main/index.ts',
+ onstart(options) {
+ if (process.env.VSCODE_DEBUG) {
+ console.log(/* For `.vscode/.debug.script.mjs` */'[startup] Electron App')
+ } else {
+ options.startup()
+ }
+ },
+ vite: {
+ build: {
+ sourcemap,
+ minify: isBuild,
+ outDir: 'dist-electron/main',
+ rollupOptions: {
+ external: Object.keys('dependencies' in pkg ? pkg.dependencies : {}),
+ },
+ },
+ },
+ },
+ {
+ entry: 'electron/preload/index.ts',
+ onstart(options) {
+ // Notify the Renderer-Process to reload the page when the Preload-Scripts build is complete,
+ // instead of restarting the entire Electron App.
+ options.reload()
+ },
+ vite: {
+ build: {
+ sourcemap: sourcemap ? 'inline' : undefined, // #332
+ minify: isBuild,
+ outDir: 'dist-electron/preload',
+ rollupOptions: {
+ external: Object.keys('dependencies' in pkg ? pkg.dependencies : {}),
+ },
+ },
+ },
+ }
+ ]),
+ // Use Node.js API in the Renderer-process
+ renderer({
+ nodeIntegration: true,
+ }),
+ ],
+ server: process.env.VSCODE_DEBUG && (() => {
+ const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL)
+ return {
+ host: url.hostname,
+ port: +url.port,
+ }
+ })(),
+ clearScreen: false,
+ }
+})