fix(app): add Vite dev workflow, fix onLayout prop, fix icon path, allow Google Fonts CSP

The v5.0.0 React UI redesign shipped without a working dev workflow —
`npm start` only ran `electron .` which loaded the source index.html
that references raw .tsx files. The browser couldn't execute them, so
the app rendered an empty #root and the user saw 'lot of errors'.

This commit restores a real dev workflow:

1. **Vite dev server wired into npm scripts** — added `concurrently`
   + `wait-on` as devDeps. `npm run dev` now runs Vite (port 5173)
   and Electron together with `wait-on tcp:5173` so Electron only
   starts after the dev server is ready.

2. **Main process loads Vite URL in dev, dist/ in prod** — window
   module now checks `process.env.VITE_DEV_SERVER_URL` and
   `app.isPackaged` to decide what to load. Production still
   loads the built `dist/renderer/index.html`.

3. **Fixed ReferenceError: app is not defined** — window module
   referenced `app.isPackaged` but only imported `BrowserWindow`.
   Added `app` to the destructured import.

4. **Fixed wrong icon path** — window creation used
   `../../assets/icon.png` from src/main/window/ which resolved
   to `src/assets/icon.png` (doesn't exist). Icon lives at
   project root, so path is now `../../../assets/icon.png`.

5. **Allowed Google Fonts in CSP** — the strict CSP
   (`font-src 'self' data:`, `connect-src 'self'`) blocked
   the preconnect/css link to fonts.googleapis.com / .gstatic.com.
   Added both domains so Plus Jakarta Sans loads.

6. **Renamed onLayout → onLayoutChange** in AppShell — react-resizable-panels
   v4 renamed the prop. The v1 name was being spread to a DOM
   div and React logged 'Unknown event handler property' warnings.
   Test mock updated for parity.

7. **show: false → show: true** — ready-to-show was hanging on
   this Wayland/container combo. Now the window is shown
   immediately on create.

Verified end-to-end:
- 305/305 vitest tests pass
- Vite dev server starts on :5173
- Electron loads localhost:5173 and React mounts
- Header 'MarkdownConverter' + sidebar with 'No files open' visible
- No onLayout warnings after HMR
- All blocked errors resolved
This commit is contained in:
2026-06-06 16:17:16 +05:30
parent 8027d0b9b5
commit 7c1a79c724
6 changed files with 423 additions and 12 deletions
+17 -4
View File
@@ -1,8 +1,9 @@
// src/main/window/index.js
// Main window creation
const { BrowserWindow } = require('electron');
const { app, BrowserWindow } = require('electron');
const path = require('path');
const fs = require('fs');
const state = require('./state');
const menu = require('../menu');
@@ -13,16 +14,28 @@ function createMainWindow() {
height: bounds.height,
x: bounds.x,
y: bounds.y,
show: false,
show: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
spellcheck: true
},
icon: path.join(__dirname, '../../assets/icon.png')
icon: path.join(__dirname, '../../../assets/icon.png')
});
win.loadFile(path.join(__dirname, '../../renderer/index.html'));
// Dev (Vite): load the running dev server so .tsx is transformed on the fly.
// Production: load the built dist/renderer/index.html (Vite output).
// VITE_DEV_SERVER_URL is set by `npm run dev` via cross-env.
// app.isPackaged is set by electron-builder for installer builds.
const devServerUrl = process.env.VITE_DEV_SERVER_URL;
if (!app.isPackaged && devServerUrl) {
console.log('[WINDOW] Dev mode — loading', devServerUrl);
win.loadURL(devServerUrl);
} else {
const prodPath = path.join(__dirname, '../../dist/renderer/index.html');
console.log('[WINDOW] Production mode — loading', prodPath);
win.loadFile(prodPath);
}
// Show window only after content is ready — avoids blank flash
win.once('ready-to-show', () => {