Electron Desktop Template
The Electron Desktop template provides a modern desktop application development environment with Electron + Vue 3 + TypeScript + Vite. It's perfect for building cross-platform desktop applications using web technologies.
Technical Stack
- Electron - Build cross-platform desktop apps with web technologies
- Vue 3 - Progressive JavaScript framework
- TypeScript - Type-safe development
- Vite - Fast build tool and dev server
- Vue Router - Official routing library (Hash mode for Electron)
- Pinia - State management library
- Vue i18n - Internationalization
- Tailwind CSS - Utility-first CSS framework
- SCSS - CSS preprocessor
- Electron Forge - Application packaging and distribution
Quick Start
1. Create Project
# Initialize project
vup init my-desktop-project
cd my-desktop-project
# Add Electron template
vup add my-electron-app
2. Install Dependencies
# Install dependencies
pnpm install
3. Start Development
# Start Electron development server
cd apps/my-electron-app
pnpm dev
The Electron application will launch automatically with hot reload support.
Project Structure
apps/my-electron-app/
├── src/
│ ├── main.ts # Main process entry
│ ├── preload.ts # Preload script
│ └── renderer/ # Renderer process (Vue app)
│ ├── assets/ # Static assets
│ │ └── images/ # Image files
│ ├── locales/ # Internationalization
│ │ ├── index.ts # i18n configuration
│ │ ├── en_US.ts # English translations
│ │ └── zh_CN.ts # Chinese translations
│ ├── router/ # Vue Router (Hash mode)
│ │ ├── index.ts # Router configuration
│ │ └── routes.ts # Route definitions
│ ├── views/ # Page components
│ │ ├── demo/ # Demo pages
│ │ ├── docs/ # Documentation pages
│ │ ├── empty/ # Empty state pages
│ │ └── index/ # Home page
│ ├── App.vue # Root component
│ ├── main.ts # Renderer entry point
│ └── index.css # Global styles
├── .vite/ # Vite build cache
├── out/ # Build output directory
├── forge.config.ts # Electron Forge configuration
├── vite.main.config.ts # Main process Vite config
├── vite.preload.config.ts # Preload script Vite config
├── vite.renderer.config.ts # Renderer process Vite config
├── package.json # Dependencies and scripts
└── tsconfig.json # TypeScript configuration
Core Features
Electron Main Process
// src/main.ts
import { app, BrowserWindow } from 'electron';
import { createWindow } from './window';
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
Electron Preload Script
// src/preload.ts
import { contextBridge, ipcRenderer } from 'electron';
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld('electronAPI', {
// Example API
getVersion: () => ipcRenderer.invoke('get-version'),
});
Vue 3 Renderer Process
<template>
<div class="container">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
<button @click="increment">Count: {{ count }}</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
const count = ref(0);
const title = ref('Electron + Vue 3 App');
const description = computed(() => `Current count is ${count.value}`);
const increment = () => {
count.value++;
};
</script>
Hash Mode Routing
Important: Electron applications must use Hash mode routing, not History mode.
// router/index.ts
import { createRouter, createWebHashHistory } from 'vue-router';
export default createRouter({
history: createWebHashHistory(), // Use Hash mode for Electron
routes,
});
Desktop-Optimized Styling
<template>
<div class="min-h-screen bg-gray-100">
<header class="bg-white shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold text-gray-900">
{{ $t('common.title') }}
</h1>
</div>
</header>
<main class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div class="px-4 py-6 sm:px-0">
<div class="border-4 border-dashed border-gray-200 rounded-lg h-96">
<p class="text-center text-gray-500 mt-20">
{{ $t('common.description') }}
</p>
</div>
</div>
</main>
</div>
</template>
Development Tools
Vite Configuration
The template uses separate Vite configurations for different processes:
// vite.main.config.ts - Main process
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/main.ts'),
formats: ['cjs'],
fileName: () => 'main.js',
},
rollupOptions: {
external: ['electron'],
},
},
});
// vite.renderer.config.ts - Renderer process
export default defineConfig({
plugins: [
vue(),
vueJsx(),
AutoImport({
imports: ['vue', 'vue-router', 'pinia', 'vue-i18n'],
dts: path.resolve(__dirname, 'auto-imports.d.ts'),
vueTemplate: true,
}),
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@shared': path.resolve(__dirname, '../../_shared'),
},
},
});
Electron Forge Configuration
// forge.config.ts
import type { ForgeConfig } from '@electron-forge/shared-types';
const config: ForgeConfig = {
packagerConfig: {
asar: true,
},
rebuildConfig: {},
makers: [
{
name: '@electron-forge/maker-squirrel',
config: {},
},
{
name: '@electron-forge/maker-zip',
platforms: ['darwin'],
},
{
name: '@electron-forge/maker-deb',
config: {},
},
{
name: '@electron-forge/maker-rpm',
config: {},
},
],
plugins: [
{
name: '@electron-forge/plugin-auto-unpack-natives',
config: {},
},
{
name: '@electron-forge/plugin-vite',
config: {
build: [
{
entry: 'src/main.ts',
config: 'vite.main.config.ts',
bundleConfig: {
external: ['electron'],
},
},
{
entry: 'src/preload.ts',
config: 'vite.preload.config.ts',
},
{
entry: 'src/renderer/main.ts',
config: 'vite.renderer.config.ts',
},
],
},
},
],
};
export default config;
Available Scripts
{
"scripts": {
"dev": "electron-forge start",
"build": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "eslint src/ --ext .vue,.ts,.js",
"lint:fix": "eslint src/ --ext .vue,.ts,.js --fix",
"format": "prettier --write \"src/**/*.{js,ts,vue,json,css,scss}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json,css,scss}\""
}
}
Building and Distribution
Development Build
# Start development server with hot reload
pnpm dev
Production Build
# Package the application
pnpm build
Create Installers
# Create platform-specific installers
pnpm make
This creates installers for:
- Windows:
.exe
installer - macOS:
.zip
archive - Linux:
.deb
and.rpm
packages
Publish Application
# Publish to distribution platforms
pnpm publish
Monorepo Considerations
Important: In monorepo projects, Electron binaries may not install correctly. If you encounter:
Error: Electron failed to install correctly, please delete node_modules/electron and try installing again
This is a common issue in monorepo projects - please follow these steps to resolve:
Solution
Clean and reinstall:
bash# Delete Electron related files rm -rf node_modules/electron # Reinstall pnpm install electron --force
🔥 Critical Step: Manually run Electron install script
This step is very important! Electron binaries need to be downloaded manually:
bash# Navigate to Electron directory cd node_modules/electron # Manually run install script (downloads binary files) node install.js
Explanation: In monorepo environments, pnpm's symlink mechanism may cause Electron's install script to not execute properly, so you need to manually run
install.js
to download platform-specific binary files.Verify installation:
bash# Check Electron version (should show version number, not error) npx electron --version
Start the application:
bash# Return to project root cd ../.. # Start Electron application pnpm dev
5. If still failing
If the above steps still fail, try a complete cleanup:
# Complete cleanup
rm -rf node_modules pnpm-lock.yaml
# Clear pnpm cache
pnpm store prune
# Reinstall
pnpm install
# Manually run Electron install script
cd node_modules/electron && node install.js
# Return to project root
cd ../..
# Start application
pnpm dev
Best Practices
Security
- Use
contextBridge
for secure IPC communication - Disable Node.js integration in renderer process
- Use preload scripts for safe API exposure
- Validate all user inputs
Performance
- Use Vite for fast development and optimized builds
- Implement code splitting for large applications
- Optimize images and assets
- Use Electron's built-in performance tools
Cross-Platform Development
- Test on all target platforms
- Handle platform-specific features gracefully
- Use Electron's platform detection APIs
- Follow platform-specific UI guidelines