Skip to main content
desktop-app Desktop app development guide — Electron and Tauri for cross-platform apps.
Triggers: desktop app, Electron, Tauri, mac app, windows app
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/popup-studio-ai/bkit-claude-code --skill desktop-app命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills bkend.ai authentication — email/social login, JWT tokens, RBAC, session management.
Triggers: bkend auth, bkend login, bkend signup, bkend JWT, bkend RBAC
bkend.ai project tutorials (todo to SaaS) and common error troubleshooting.
Triggers: bkend tutorial, bkend cookbook, bkend troubleshooting
bkend.ai database — CRUD, column types, filtering, sorting, relations, indexing.
Triggers: bkend table, bkend CRUD, bkend column, bkend relation, bkend data
name desktop-app classification capability classification-reason Specialized domain knowledge with limited model overlap deprecation-risk low effort low description Desktop app development guide — Electron and Tauri for cross-platform apps.
Triggers: desktop app, Electron, Tauri, mac app, windows app
agent bkit:pipeline-guide allowed-tools ["Read","Write","Edit","Glob","Grep","Bash","WebSearch"] user-invocable true
Desktop App Development Expertise
Overview
A guide for developing desktop apps using web technologies (HTML, CSS, JavaScript).
Support Windows, macOS, and Linux simultaneously with a single codebase.
Framework Selection Guide
Framework Selection by Tier (v1.3.0)
Framework Tier Recommendation Use Case Tauri Tier 2 ⭐ Primary Lightweight (3MB), Rust security Electron Tier 3 Supported Mature ecosystem, VS Code-like apps
AI-Native Recommendation : Tauri
35% YoY growth
20-40MB memory vs Electron's 200-400MB
Mobile support (iOS/Android) via Tauri 2.0
Rust backend = memory safety
Ecosystem Recommendation : Electron
Mature tooling
Node.js integration
Proven at scale (VS Code, Slack)
Level-wise Recommendations
Starter → Tauri (v2) [Tier 2]
- Simpler setup than Electron
- Smaller output bundles (~3MB vs ~150MB)
Dynamic → Tauri + auto-update [Tier 2]
- Includes server integration, auto-update
- Lower memory footprint
Enterprise → Tauri [Tier 2] or Electron [Tier 3]
- Tauri for performance and security
- Electron for complex Node.js integration
Electron Guide
Project Creation
npm create @electron-vite/create my-electron-app
cd my-electron-app
npm install
npm run dev
Folder Structure
my-electron-app/
├── src/
│ ├── main/ # Main process (Node.js)
│ │ └── index.ts # App entry point, window management
│ ├── preload/ # Preload script
│ │ └── index.ts # Renderer↔Main bridge
│ └── renderer/ # Renderer process (Web)
│ ├── src/ # React/Vue code
│ └── index.html # HTML entry point
├── resources/ # App icons, assets
├── electron.vite.config.ts # Build configuration
├── electron-builder.yml # Deployment configuration
└── package.json
Core Concept: Process Separation ┌─────────────────────────────────────────────────────┐
│ Electron App │
├─────────────────────────────────────────────────────┤
│ Main Process (Node.js) │
│ - System API access (files, network, etc.) │
│ - Window creation/management │
│ - Menu, tray management │
├─────────────────────────────────────────────────────┤
│ Preload Script (Bridge) │
│ - Safe main↔renderer communication │
│ - Expose only specific APIs │
├─────────────────────────────────────────────────────┤
│ Renderer Process (Chromium) │
│ - Web UI (React, Vue, etc.) │
│ - DOM access │
│ - No direct Node.js API access (security) │
└─────────────────────────────────────────────────────┘
Main Process
import { app, BrowserWindow , ipcMain } from 'electron' ;
import { join } from 'path' ;
let mainWindow : BrowserWindow | null = null ;
function createWindow ( ) {
mainWindow = new BrowserWindow ({
width : 1200 ,
height : 800 ,
webPreferences : {
preload : join (__dirname, '../preload/index.js' ),
sandbox : false ,
},
});
if (process.env .NODE_ENV === 'development' ) {
mainWindow.loadURL ('http://localhost:5173' );
mainWindow.webContents .openDevTools ();
} else {
mainWindow.loadFile (join (__dirname, '../renderer/index.html' ));
}
}
app.whenReady ().then (createWindow);
app.on ('window-all-closed' , () => {
if (process.platform !== 'darwin' ) {
app.quit ();
}
});
ipcMain.handle ('read-file' , async (event, filePath) => {
const fs = await import ('fs/promises' );
return fs.readFile (filePath, 'utf-8' );
});
Preload Script
import { contextBridge, ipcRenderer } from 'electron' ;
contextBridge.exposeInMainWorld ('electronAPI' , {
readFile : (filePath : string ) => ipcRenderer.invoke ('read-file' , filePath),
saveFile : (content : string ) => ipcRenderer.invoke ('save-file' , content),
getVersion : () => process.env .npm_package_version ,
platform : process.platform ,
});
declare global {
interface Window {
electronAPI : {
readFile : (path : string ) => Promise <string >;
saveFile : (content : string ) => Promise <void >;
getVersion : () => string ;
platform : NodeJS .Platform ;
};
}
}
Renderer Process
import { useState } from 'react' ;
function App ( ) {
const [content, setContent] = useState ('' );
const handleOpenFile = async ( ) => {
const result = await window .electronAPI .readFile ('/path/to/file.txt' );
setContent (result);
};
return (
<div className ="app" >
<h1 > My Electron App</h1 >
<p > Platform: {window.electronAPI.platform}</p >
<button onClick ={handleOpenFile} > Open File</button >
<pre > {content}</pre >
</div >
);
}
export default App ;
Creating Menus
import { Menu , app, shell } from 'electron' ;
const template : Electron .MenuItemConstructorOptions [] = [
{
label : 'File' ,
submenu : [
{ label : 'New File' , accelerator : 'CmdOrCtrl+N' , click : () => {} },
{ label : 'Open' , accelerator : 'CmdOrCtrl+O' , click : () => {} },
{ type : 'separator' },
{ label : 'Quit' , role : 'quit' },
],
},
{
label : 'Edit' ,
submenu : [
{ label : 'Undo' , role : 'undo' },
{ label : 'Redo' , role : 'redo' },
{ type : 'separator' },
{ label : 'Cut' , role : 'cut' },
{ label : 'Copy' , role : 'copy' },
{ label : 'Paste' , role : 'paste' },
],
},
{
label : 'Help' ,
submenu : [
{
label : 'Documentation' ,
click : () => shell.openExternal ('https://docs.example.com' ),
},
],
},
];
if (process.platform === 'darwin' ) {
template.unshift ({
label : app.getName (),
submenu : [
{ role : 'about' },
{ type : 'separator' },
{ role : 'services' },
{ type : 'separator' },
{ role : 'hide' },
{ role : 'unhide' },
{ type : 'separator' },
{ role : 'quit' },
],
});
}
export const menu = Menu .buildFromTemplate (template);
System Tray
import { Tray , Menu , nativeImage } from 'electron' ;
import { join } from 'path' ;
let tray : Tray | null = null ;
export function createTray ( ) {
const icon = nativeImage.createFromPath (join (__dirname, '../../resources/icon.png' ));
tray = new Tray (icon.resize ({ width : 16 , height : 16 }));
const contextMenu = Menu .buildFromTemplate ([
{ label : 'Open' , click : () => {} },
{ type : 'separator' },
{ label : 'Quit' , role : 'quit' },
]);
tray.setToolTip ('My App' );
tray.setContextMenu (contextMenu);
}
Tauri Guide
Project Creation
npm create tauri-app my-tauri-app
cd my-tauri-app
npm install
npm run tauri dev
Folder Structure my-tauri-app/
├── src/ # Frontend (React, Vue, etc.)
│ ├── App.tsx
│ └── main.tsx
├── src-tauri/ # Tauri backend (Rust)
│ ├── src/
│ │ ├── main.rs # Main entry point
│ │ └── lib.rs # Command definitions
│ ├── tauri.conf.json # Tauri configuration
│ └── Cargo.toml # Rust dependencies
├── public/
└── package.json
Command Definition (Rust)
use tauri::command;
#[command]
fn greet (name: &str ) -> String {
format! ("Hello, {}!" , name)
}
#[command]
async fn read_file (path: &str ) -> Result <String , String > {
std::fs::read_to_string (path)
.map_err (|e| e.to_string ())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run () {
tauri::Builder::default ()
.invoke_handler (tauri::generate_handler![greet, read_file])
.run (tauri::generate_context!())
.expect ("error while running tauri application" );
}
Calling from Frontend
import { invoke } from '@tauri-apps/api/core' ;
function App ( ) {
const [greeting, setGreeting] = useState ('' );
const handleGreet = async ( ) => {
const result = await invoke ('greet' , { name : 'World' });
setGreeting (result as string );
};
const handleReadFile = async ( ) => {
try {
const content = await invoke ('read_file' , { path : '/path/to/file.txt' });
console .log (content);
} catch (error) {
console .error (error);
}
};
return (
<div >
<button onClick ={handleGreet} > Greet</button >
<p > {greeting}</p >
</div >
);
}
Web vs Desktop Differences
File System Access
const fs = require ('fs' );
fs.writeFileSync ('/path/to/file.txt' , 'content' );
await invoke ('write_file' , { path : '/path/to/file.txt' , content : 'content' });
System Integration Things impossible on web but possible on desktop:
- System tray icon
- Global shortcuts
- Native notifications
- Drag and drop (file path access)
- Full clipboard control
- Native menus
Offline Support Web: Requires Service Worker, limited
Desktop: Works offline by default
⚠️ Server integration features must handle offline!
Build & Deployment
Electron Build
appId: com.example.myapp
productName: My App
directories:
buildResources: resources
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.*'
mac:
artifactName: ${name}-${version}-${arch}.${ext}
target:
- dmg
- zip
icon: resources/icon.icns
win:
artifactName: ${name}-${version}-${arch}.${ext}
target:
- nsis
icon: resources/icon.ico
linux:
target:
- AppImage
- deb
npm run build:mac
npm run build:win
npm run build:linux
Auto-update
import { autoUpdater } from 'electron-updater' ;
autoUpdater.checkForUpdatesAndNotify ();
autoUpdater.on ('update-available' , () => {
});
autoUpdater.on ('update-downloaded' , () => {
autoUpdater.quitAndInstall ();
});
Tauri Build
Desktop PDCA Checklist
Phase 1: Schema □ Decide local data storage method (SQLite, JSON file, etc.)
□ Decide if cloud sync is needed
Phase 3: Mockup □ Consider platform-specific UI guidelines (macOS, Windows)
□ Plan keyboard shortcuts
□ Design menu structure
Phase 6: UI □ Support dark/light mode
□ Handle window resizing
□ Handle platform-specific UI differences (window control positions, etc.)
Phase 7: Security □ Don't expose Node.js APIs directly (use contextBridge)
□ Security handling when loading external URLs
□ Encrypt sensitive data storage
Phase 9: Deployment □ Code signing (macOS Notarization, Windows Signing)
□ Set up auto-update
□ App Store submission (if needed)
Useful Libraries
Electron Library Purpose electron-store Local settings/data storage electron-updater Auto-update electron-log Logging better-sqlite3 SQLite database
Tauri Library Purpose tauri-plugin-store Settings storage tauri-plugin-sql SQLite support tauri-plugin-log Logging tauri-plugin-updater Auto-update
Requesting from Claude
Project Creation "Set up a [app description] app project with Electron + React.
- Use electron-vite
- Support system tray
- Set up auto-update"
Feature Implementation "Implement file open/save functionality.
- Use native file dialogs
- Save recent file list
- Support drag and drop"
Build Configuration "Create electron-builder configuration.
- macOS: DMG + notarization
- Windows: NSIS installer
- Auto-update server integration"