setup electron and vite
December 08, 2025
(Last updated: December 08, 2025)
3 min read
After a long time, I'm back. This post will be more for me than for you.
Recently I had an idea for a desktop application and had a lot of trouble finding material explaining how to configure it to use TypeScript + React + Electron. So, after a lot of research, I'm going to document how I configured everything.
Setup React + Typescript
When I'm developing something with React, I always prefer to use Vite, so it won't be any different here.
mkdir my-app
cd my-app
npm create vite@latest . -- --template react-ts
npm install
This is the standard setup for running in a browser at http://localhost:5173.
Installing Electron
npm install --save-dev electron
npm install --save-dev concurrently cross-env wait-on
npm install --save-dev @types/node
I also install some tools that I will need.
concurrently: allows you to run Vite and Electron at the same time.cross-env: sets environment variables in a Windows-compatible way.wait-on: waits for the Vite server to start up before opening Electron.
Configuring Electron
mkdir electron
cd electron
New-Item main.ts //or touch main.ts
New-Item preload.ts //or touch preload.ts
New-Item tsconfig.json //or touch tsconfig.json
cd ..
The structure will look like this:
my-app
- electron
- main.ts
- preload.ts
- tsconfig.json
- src
- ...
- package.json
- index.html
- tsconfig.json
- vite.config.js
- ...
in electron/tsconfig.json, put the typescript settings
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "Node",
"outDir": "../dist-electron",
"rootDir": "./",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"types": ["node"]
},
"include": ["./**/*.ts"]
}
Main settings
for the file electron/main.ts:
import { app, BrowserWindow } from "electron";
import path from "node:path";
import { fileURLToPath } from "node:url";
const isDev = process.env.NODE_ENV === "development";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
let mainWindow: BrowserWindow | null = null;
async function createWindow() {
mainWindow = new BrowserWindow({
width: 1000,
height: 700,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
contextIsolation: true
}
});
if (isDev) {
await mainWindow.loadURL("http://localhost:5173");
mainWindow.webContents.openDevTools();
} else {
const indexPath = path.join(__dirname, "../dist/index.html");
await mainWindow.loadFile(indexPath);
}
mainWindow.on("closed", () => {
mainWindow = null;
});
}
app.whenReady().then(() => {
createWindow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
And on electron/preload.ts:
export {};
It will be compiled into dist-electron/preload.js and loaded into the BrowserWindow's webPreferences.
in the package.json file in the project root add:
"main": "dist-electron/main.js",
And change the scripts section to:
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"build:electron": "tsc -p electron/tsconfig.json",
"build:all": "npm run build && npm run build:electron",
"electron": "wait-on http://localhost:5173 && electron .",
"dev:electron": "cross-env NODE_ENV=development concurrently \"npm run dev\" \"npm run electron\""
},
Running
Now that everything is configured, run the following command to execute the application.
npm run build:all
npm run dev:electron
That's it.
I hope this helped if you were having difficulty like I was.