Struttura di un Progetto Electron
Una buona struttura del progetto è fondamentale per mantenere il codice organizzato e scalabile. Electron non impone una struttura rigida, ma ci sono convenzioni consolidate dalla community.
Struttura Base
Un progetto Electron minimale ha questa struttura:
mia-app/
├── package.json # Configurazione e dipendenze
├── main.js # Entry point - Main Process
├── preload.js # Script di preload
├── index.html # Pagina principale
├── renderer.js # Logica del renderer
└── styles.css # Stili
Struttura Consigliata per Progetti Reali
Per applicazioni più complesse, è consigliato separare il codice per responsabilità:
mia-app/
├── package.json
├── forge.config.js # Configurazione Electron Forge
│
├── src/
│ ├── main/ # Codice del Main Process
│ │ ├── main.js # Entry point principale
│ │ ├── menu.js # Menu dell'applicazione
│ │ ├── tray.js # System tray
│ │ ├── ipc.js # Handler IPC
│ │ └── updater.js # Auto-updater
│ │
│ ├── preload/ # Preload scripts
│ │ └── preload.js # Bridge tra main e renderer
│ │
│ ├── renderer/ # Codice del Renderer Process
│ │ ├── index.html # Pagina principale
│ │ ├── app.js # Logica applicazione
│ │ ├── styles.css # Stili
│ │ └── pages/ # Pagine aggiuntive
│ │ ├── settings.html
│ │ └── about.html
│ │
│ └── shared/ # Codice condiviso
│ ├── constants.js # Costanti condivise
│ └── utils.js # Utility condivise
│
├── assets/ # Risorse statiche
│ ├── icons/ # Icone dell'app
│ │ ├── icon.png
│ │ ├── icon.ico
│ │ └── icon.icns
│ └── images/ # Altre immagini
│
├── dist/ # File compilati (generato)
└── out/ # Pacchetti distribuibili (generato)
Ruolo di Ogni Cartella
src/main/
Contiene tutto il codice che gira nel Main Process. Qui hai accesso completo alle API di Node.js e alle API native di Electron:
// src/main/main.js
const { app, BrowserWindow } = require('electron');
const path = require('node:path');
const { setupMenu } = require('./menu');
const { setupIPC } = require('./ipc');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
preload: path.join(__dirname, '..', 'preload', 'preload.js'),
},
});
mainWindow.loadFile(
path.join(__dirname, '..', 'renderer', 'index.html')
);
return mainWindow;
}
app.whenReady().then(() => {
const mainWindow = createWindow();
setupMenu(mainWindow);
setupIPC(mainWindow);
});
src/preload/
Contiene i preload script che fungono da ponte sicuro tra Main Process e Renderer Process:
// src/preload/preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile'),
saveFile: (data) => ipcRenderer.invoke('dialog:saveFile', data),
onUpdateAvailable: (callback) =>
ipcRenderer.on('update-available', callback),
});
src/renderer/
Contiene tutto il codice dell’interfaccia utente. Qui scrivi HTML, CSS e JavaScript come in un’applicazione web tradizionale:
<!-- src/renderer/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'">
<title>La Mia App</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="app">
<nav id="sidebar"><!-- Navigazione --></nav>
<main id="content"><!-- Contenuto --></main>
</div>
<script src="app.js"></script>
</body>
</html>
src/shared/
Codice e costanti condivise tra Main e Renderer Process:
// src/shared/constants.js
module.exports = {
IPC_CHANNELS: {
OPEN_FILE: 'dialog:openFile',
SAVE_FILE: 'dialog:saveFile',
GET_SETTINGS: 'settings:get',
SET_SETTINGS: 'settings:set',
},
APP_NAME: 'La Mia App',
DEFAULT_WINDOW_SIZE: { width: 1200, height: 800 },
};
assets/
Risorse statiche come icone, immagini e font. Le icone dell’applicazione devono essere nei formati corretti per ogni piattaforma:
- Windows:
.ico(256x256) - macOS:
.icns - Linux:
.png(512x512)
Configurazione del package.json
Il package.json deve puntare all’entry point corretto:
{
"name": "mia-app",
"version": "1.0.0",
"main": "src/main/main.js",
"scripts": {
"start": "electron .",
"build": "electron-forge make",
"package": "electron-forge package"
},
"devDependencies": {
"electron": "^33.0.0"
}
}
Struttura con Framework Frontend
Se usi un framework come React, Vue o Svelte per il renderer, la struttura si adatta:
mia-app/
├── package.json
├── vite.config.js # Bundler per il renderer
│
├── src/
│ ├── main/ # Main Process (invariato)
│ │ └── main.js
│ │
│ ├── preload/ # Preload (invariato)
│ │ └── preload.js
│ │
│ └── renderer/ # Ora con framework
│ ├── index.html
│ ├── App.jsx # Componente root React/Vue/etc
│ ├── main.jsx # Entry point del framework
│ └── components/ # Componenti UI
│
└── electron-builder.yml # Config distribuzione
Best Practice
- Separare i processi: Mai mischiare codice Main e Renderer nella stessa cartella
- Centralizzare le costanti IPC: Usare
shared/constants.jsper i nomi dei canali IPC evita errori di digitazione - Un file per responsabilità: Separare menu, tray, IPC handlers e updater in file dedicati
- Assets organizzati: Tenere le icone separate dalle immagini dell’app
- Ignorare le cartelle generate: Aggiungere
dist/eout/al.gitignore