chore: starter

This commit is contained in:
2026-01-29 14:58:22 +08:00
parent a74e8d3034
commit 0c0fdeda8f
28 changed files with 2330 additions and 246 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
node_modules node_modules
dist dist
dist-web
out out
.DS_Store .DS_Store
.eslintcache .eslintcache

View File

@@ -1,6 +0,0 @@
out
dist
pnpm-lock.yaml
LICENSE.md
tsconfig.json
tsconfig.*.json

View File

@@ -1,4 +0,0 @@
singleQuote: true
semi: false
printWidth: 100
trailingComma: none

BIN
build/ico.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -1,6 +1,10 @@
import { resolve } from 'path' import { resolve } from 'node:path'
import { defineConfig } from 'electron-vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { defineConfig } from 'electron-vite'
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
export default defineConfig({ export default defineConfig({
main: {}, main: {},
@@ -8,9 +12,21 @@ export default defineConfig({
renderer: { renderer: {
resolve: { resolve: {
alias: { alias: {
'@renderer': resolve('src/renderer/src') '@renderer': resolve('src/renderer/src'),
} },
},
plugins: [
vue(),
vueJsx(),
// 配置自动导入
AutoImport({
resolvers: [ElementPlusResolver()],
dts: true,
}),
Components({
resolvers: [ElementPlusResolver()],
dts: true,
}),
],
}, },
plugins: [vue()]
}
}) })

View File

@@ -1,40 +1,4 @@
import { defineConfig } from 'eslint/config' // eslint.config.mjs
import tseslint from '@electron-toolkit/eslint-config-ts' import antfu from '@antfu/eslint-config'
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier'
import eslintPluginVue from 'eslint-plugin-vue'
import vueParser from 'vue-eslint-parser'
export default defineConfig( export default antfu()
{ ignores: ['**/node_modules', '**/dist', '**/out'] },
tseslint.configs.recommended,
eslintPluginVue.configs['flat/recommended'],
{
files: ['**/*.vue'],
languageOptions: {
parser: vueParser,
parserOptions: {
ecmaFeatures: {
jsx: true
},
extraFileExtensions: ['.vue'],
parser: tseslint.parser
}
}
},
{
files: ['**/*.{ts,mts,tsx,vue}'],
rules: {
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'vue/block-lang': [
'error',
{
script: {
lang: 'ts'
}
}
]
}
},
eslintConfigPrettier
)

View File

@@ -1,46 +1,48 @@
{ {
"name": "cslab-dcs-web", "name": "cslab-dcs-web",
"version": "1.0.0", "version": "1.0.0",
"description": "An Electron application with Vue and TypeScript", "description": "CSLAB DCS 编辑器",
"author": "CSLAB FE",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "example.com",
"homepage": "https://electron-vite.org",
"scripts": { "scripts": {
"format": "prettier --write .",
"lint": "eslint --cache .",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"start": "electron-vite preview",
"dev": "electron-vite dev", "dev": "electron-vite dev",
"dev:web": "vite --config vite.config.web.ts",
"build:web": "vite build --config vite.config.web.ts",
"start": "electron-vite preview",
"build": "npm run typecheck && electron-vite build", "build": "npm run typecheck && electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir", "build:unpack": "npm run build && electron-builder --dir",
"build:win": "npm run build && electron-builder --win", "build:win": "npm run build && electron-builder --win",
"build:mac": "npm run build && electron-builder --mac", "build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux" "build:linux": "npm run build && electron-builder --linux",
"lint": "eslint --cache .",
"format": "eslint --cache . --fix",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"postinstall": "electron-builder install-app-deps"
}, },
"dependencies": { "dependencies": {
"@electron-toolkit/preload": "^3.0.2", "@electron-toolkit/preload": "^3.0.2",
"@electron-toolkit/utils": "^4.0.0", "@electron-toolkit/utils": "^4.0.0",
"electron-updater": "^6.3.9" "electron-updater": "^6.3.9",
"element-plus": "^2.13.1",
"vue-router": "^4.6.4"
}, },
"devDependencies": { "devDependencies": {
"@electron-toolkit/eslint-config-prettier": "3.0.0", "@antfu/eslint-config": "^7.2.0",
"@electron-toolkit/eslint-config-ts": "^3.1.0",
"@electron-toolkit/tsconfig": "^2.0.0", "@electron-toolkit/tsconfig": "^2.0.0",
"@types/node": "^22.19.1", "@types/node": "^22.19.1",
"@vitejs/plugin-vue": "^6.0.2", "@vitejs/plugin-vue": "^6.0.2",
"@vitejs/plugin-vue-jsx": "^5.1.3",
"electron": "^39.2.6", "electron": "^39.2.6",
"electron-builder": "^26.0.12", "electron-builder": "^26.0.12",
"electron-vite": "^5.0.0", "electron-vite": "^5.0.0",
"eslint": "^9.39.1", "eslint": "^9.39.1",
"eslint-plugin-vue": "^10.6.2",
"prettier": "^3.7.4",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"unplugin-auto-import": "^21.0.0",
"unplugin-vue-components": "^31.0.0",
"vite": "^7.2.6", "vite": "^7.2.6",
"vue": "^3.5.25", "vue": "^3.5.25",
"vue-eslint-parser": "^10.2.0",
"vue-tsc": "^3.1.6" "vue-tsc": "^3.1.6"
}, },
"pnpm": { "pnpm": {

2205
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -1,6 +1,7 @@
import { app, shell, BrowserWindow, ipcMain } from 'electron' import { join } from 'node:path'
import { join } from 'path' import process from 'node:process'
import { electronApp, optimizer, is } from '@electron-toolkit/utils' import { electronApp, is, optimizer } from '@electron-toolkit/utils'
import { app, BrowserWindow, ipcMain, shell } from 'electron'
import icon from '../../resources/icon.png?asset' import icon from '../../resources/icon.png?asset'
function createWindow(): void { function createWindow(): void {
@@ -13,8 +14,8 @@ function createWindow(): void {
...(process.platform === 'linux' ? { icon } : {}), ...(process.platform === 'linux' ? { icon } : {}),
webPreferences: { webPreferences: {
preload: join(__dirname, '../preload/index.js'), preload: join(__dirname, '../preload/index.js'),
sandbox: false sandbox: false,
} },
}) })
mainWindow.on('ready-to-show', () => { mainWindow.on('ready-to-show', () => {
@@ -28,9 +29,10 @@ function createWindow(): void {
// HMR for renderer base on electron-vite cli. // HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production. // Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) { if (is.dev && process.env.ELECTRON_RENDERER_URL) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL)
} else { }
else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html')) mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
} }
} }
@@ -50,14 +52,15 @@ app.whenReady().then(() => {
}) })
// IPC test // IPC test
ipcMain.on('ping', () => console.log('pong')) ipcMain.on('ping', () => console.warn('pong'))
createWindow() createWindow()
app.on('activate', function () { app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the // On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open. // dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow() if (BrowserWindow.getAllWindows().length === 0)
createWindow()
}) })
}) })

View File

@@ -1,4 +1,4 @@
import { ElectronAPI } from '@electron-toolkit/preload' import type { ElectronAPI } from '@electron-toolkit/preload'
declare global { declare global {
interface Window { interface Window {

View File

@@ -1,5 +1,6 @@
import { contextBridge } from 'electron' import process from 'node:process'
import { electronAPI } from '@electron-toolkit/preload' import { electronAPI } from '@electron-toolkit/preload'
import { contextBridge } from 'electron'
// Custom APIs for renderer // Custom APIs for renderer
const api = {} const api = {}
@@ -11,12 +12,14 @@ if (process.contextIsolated) {
try { try {
contextBridge.exposeInMainWorld('electron', electronAPI) contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api) contextBridge.exposeInMainWorld('api', api)
} catch (error) { }
catch (error) {
console.error(error) console.error(error)
} }
} else { }
// @ts-ignore (define in dts) else {
// @ts-expect-error (define in dts)
window.electron = electronAPI window.electron = electronAPI
// @ts-ignore (define in dts) // @ts-expect-error (define in dts)
window.api = api window.api = api
} }

10
src/renderer/auto-imports.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
}

26
src/renderer/components.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
/* eslint-disable */
// @ts-nocheck
// biome-ignore lint: disable
// oxlint-disable
// ------
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
import { GlobalComponents } from 'vue'
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Versions: typeof import('./src/components/Versions.vue')['default']
}
}
// For TSX support
declare global {
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
const Versions: typeof import('./src/components/Versions.vue')['default']
}

View File

@@ -1,26 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import Versions from './components/Versions.vue'
const ipcHandle = (): void => window.electron.ipcRenderer.send('ping')
</script> </script>
<template> <template>
<img alt="logo" class="logo" src="./assets/electron.svg" /> <router-view />
<div class="creator">Powered by electron-vite</div>
<div class="text">
Build an Electron app with
<span class="vue">Vue</span>
and
<span class="ts">TypeScript</span>
</div>
<p class="tip">Please try pressing <code>F12</code> to open the devTool</p>
<div class="actions">
<div class="action">
<a href="https://electron-vite.org/" target="_blank" rel="noreferrer">Documentation</a>
</div>
<div class="action">
<a target="_blank" rel="noreferrer" @click="ipcHandle">Send IPC</a>
</div>
</div>
<Versions />
</template> </template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -1,13 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import { isElectron } from '@renderer/utils/env'
import { reactive } from 'vue' import { reactive } from 'vue'
const versions = reactive({ ...window.electron.process.versions }) const versions = reactive(
isElectron()
? { ...window.electron.process.versions }
: { electron: 'N/A', chrome: 'N/A', node: 'N/A' },
)
</script> </script>
<template> <template>
<ul class="versions"> <ul class="versions">
<li class="electron-version">Electron v{{ versions.electron }}</li> <li class="electron-version">
<li class="chrome-version">Chromium v{{ versions.chrome }}</li> Electron v{{ versions.electron }}
<li class="node-version">Node v{{ versions.node }}</li> </li>
<li class="chrome-version">
Chromium v{{ versions.chrome }}
</li>
<li class="node-version">
Node v{{ versions.node }}
</li>
</ul> </ul>
</template> </template>

View File

@@ -1,6 +1,8 @@
import './assets/main.css'
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router'
createApp(App).mount('#app') import 'element-plus/dist/index.css'
import './assets/main.css'
createApp(App).use(router).mount('#app')

View File

@@ -0,0 +1,20 @@
import { isElectron } from '@renderer/utils/env'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'home',
component: () => import('@renderer/views/Home.vue'),
},
]
// Electron 使用 hash 模式Web 使用 history 模式
const router = createRouter({
history: isElectron()
? createWebHashHistory()
: createWebHistory('/dcs-web/'),
routes,
})
export default router

View File

@@ -0,0 +1,17 @@
/**
* 检测当前是否在 Electron 环境中运行
*/
export function isElectron(): boolean {
return typeof window !== 'undefined' && !!window.electron?.process?.versions
}
/**
* 获取 Electron 进程版本信息
* 在 Web 环境中返回 undefined
*/
export function getElectronVersions() {
if (isElectron()) {
return window.electron.process.versions
}
return undefined
}

View File

@@ -0,0 +1,35 @@
<script setup lang="ts">
import Versions from '@renderer/components/Versions.vue'
import { isElectron } from '@renderer/utils/env'
function ipcHandle(): void {
if (isElectron()) {
window.electron.ipcRenderer.send('ping')
}
}
</script>
<template>
<img alt="logo" class="logo" src="@renderer/assets/icon.png">
<div class="creator">
Powered by electron-vite
</div>
<div class="text">
Build an Electron app with
<span class="vue">Vue</span>
and
<span class="ts">TypeScript</span>
</div>
<p class="tip">
Please try pressing <code>F12</code> to open the devTool
</p>
<div class="actions">
<div class="action">
<a href="https://electron-vite.org/" target="_blank" rel="noreferrer">Documentation</a>
</div>
<div v-if="isElectron()" class="action">
<a target="_blank" rel="noreferrer" @click="ipcHandle">Send IPC</a>
</div>
</div>
<Versions />
</template>

View File

@@ -1,4 +1,4 @@
{ {
"files": [], "references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.web.json" }],
"references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.web.json" }] "files": []
} }

View File

@@ -1,8 +1,8 @@
{ {
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json", "extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"],
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"types": ["electron-vite/node"] "types": ["electron-vite/node"]
} },
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"]
} }

View File

@@ -1,11 +1,5 @@
{ {
"extends": "@electron-toolkit/tsconfig/tsconfig.web.json", "extends": "@electron-toolkit/tsconfig/tsconfig.web.json",
"include": [
"src/renderer/src/env.d.ts",
"src/renderer/src/**/*",
"src/renderer/src/**/*.vue",
"src/preload/*.d.ts"
],
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"baseUrl": ".", "baseUrl": ".",
@@ -14,5 +8,11 @@
"src/renderer/src/*" "src/renderer/src/*"
] ]
} }
} },
"include": [
"src/renderer/src/env.d.ts",
"src/renderer/src/**/*",
"src/renderer/src/**/*.vue",
"src/preload/*.d.ts"
]
} }

33
vite.config.web.ts Normal file
View File

@@ -0,0 +1,33 @@
import { resolve } from 'node:path'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
import { defineConfig } from 'vite'
export default defineConfig({
root: 'src/renderer',
base: '/dcs-web/',
resolve: {
alias: {
'@renderer': resolve(__dirname, 'src/renderer/src'),
},
},
build: {
outDir: resolve(__dirname, 'dist-web'),
emptyOutDir: true,
},
plugins: [
vue(),
vueJsx(),
AutoImport({
resolvers: [ElementPlusResolver()],
dts: true,
}),
Components({
resolvers: [ElementPlusResolver()],
dts: true,
}),
],
})