Update to newer electron#34
Conversation
|
Keeping a record of the notes Claude made about the path we took to get here: Modernize SamplePad Editor for macOS Tahoe / Apple SiliconContextElectron 10.1.3 has no ARM64 binary, so the app can't build on Apple Silicon. The entire build toolchain (CRA, node-sass-chokidar, craco) is deprecated. We modernized infrastructure while keeping the app functionally identical. Target: macOS only (ARM64 + x64). Final Architecture
Why not electron-vite?Initially planned to use electron-vite, but encountered bundling issues where local Implementation StepsStep 1: Restructure directoriesMoved Electron main/preload files from
Deleted: Kept: Step 2: Update dependenciesRemoved:
Installed:
Upgraded:
Kept:
Step 3: Create
|
| File | Change |
|---|---|
src/index.js |
'css/index.css' → 'css/index.scss' |
src/component/EditKit.js |
'css/EditKit.css' → 'css/EditKit.scss' |
src/component/Notice.js |
'css/Notice.css' → 'css/Notice.scss' |
src/component/SampleList.js |
'css/SampleList.css' → 'css/SampleList.scss' |
src/component/Pad/Row.js |
'css/Pad.css' → 'css/Pad.scss' |
src/component/Pad/SlideControl.js |
'css/Pad/Control.css' → 'css/Pad/Control.scss' |
src/component/Pad/KnobControl.js |
'css/Pad/Control.css' → 'css/Pad/Control.scss' |
src/component/Pad/Velocity.js |
'css/Pad/Velocity.css' → 'css/Pad/Velocity.scss' |
src/component/Pad/MuteGroup.js |
'css/Pad/MuteGroup.css' → 'css/Pad/MuteGroup.scss' |
Updated src/index.js imports:
Added direct CSS imports before SCSS:
import 'css/bulma.min.css'
import 'css/bulma-tooltip.min.css'
import 'css/icons.css'
import 'css/index.scss'Deleted generated .css files:
src/css/EditKit.csssrc/css/Notice.csssrc/css/Pad.csssrc/css/SampleList.csssrc/css/index.csssrc/css/Pad/Control.csssrc/css/Pad/MuteGroup.csssrc/css/Pad/Velocity.css
Step 10: React 18 upgrade in src/index.js
import { createRoot } from 'react-dom/client'
// ...
const root = createRoot(document.getElementById('root'))
root.render(
<Provider store={store}><App /></Provider>
)Step 11: Fix rc-slider handle prop
Both src/component/Pad/SlideControl.js and src/component/Pad/KnobControl.js:
<Slider
...
handleRender={(node, handleProps) => this.getHandle(handleProps)}
...
/>Step 12: Fix Buffer imports
Added explicit Buffer imports where needed:
src/util/buffer.js:
import { Buffer } from 'buffer'
const { fs } = window.api
export const getBuffer = (filePath) => {
return Buffer.from(fs.readFileBufferArray(filePath));
}src/util/kitFile.js:
import { Buffer } from 'buffer'
// ... rest of importsWhy: Vite doesn't provide global Buffer polyfills. Importing directly from 'buffer' package avoids polyfill conflicts.
Step 13: Update package.json
{
"name": "samplepad-editor",
"productName": "SamplePad Kit Editor",
"description": "Build drum kits for the Alesis SamplePad",
"author": "Ryan Bateman",
"version": "0.8.0",
"private": true,
"main": "electron/main.js",
"scripts": {
"dev": "concurrently \"vite\" \"wait-on http://localhost:5173 && electron .\"",
"build": "vite build",
"pack": "vite build && electron-builder build --mac"
},
"build": {
"appId": "com.electron.samplepadeditor",
"productName": "SamplePad Kit Editor",
"files": ["build/**/*", "electron/**/*"],
"directories": { "buildResources": "assets" },
"mac": {
"category": "public.app-category.music",
"target": [{ "target": "dmg", "arch": ["arm64", "x64"] }]
}
}
}Key changes:
main: "electron/main.js"- Points to unbundled main process sourcedevscript uses concurrently to run Vite + Electron in parallelwait-onensures Vite server is ready before Electron starts- Build files include both
build/(renderer) andelectron/(main/preload source)
Critical Fixes Discovered During Implementation
1. electron-store initialization
Problem: With contextIsolation: true, electron-store v7 requires initialization in both main and preload processes.
Solution: Added const store = new Store() at the top of electron/main.js before app.ready.
2. ipcMain timing
Problem: Calling ipcMain.handle() at module load time (before app is ready) causes ipcMain to be undefined.
Solution: Moved IPC handler registration into createWindow() function, which runs after app.ready.
3. ipcRenderer in main process module
Problem: electron/events/mainProcessEvents.js is loaded by electron/main.js at module load time, but tried to require ipcRenderer (only available in renderer/preload).
Solution: Only require ipcMain at top level. Require ipcRenderer inside the initIpcRendererSender() function that runs in preload context.
4. JSX in .js files
Problem: Vite doesn't treat .js files as JSX by default.
Solution: Added esbuild configuration to handle JSX in .js files:
esbuild: {
loader: 'jsx',
include: /.*\.jsx?$/
}Files with NO changes
- All Redux state (
src/state/*) - All Redux actions (
src/actions/*) - Most components (App.js, EditKit.js, Header.js, KitList.js, Modal.js, Sample.js, SamplePlayer.js, Pad/*.js except SlideControl and KnobControl)
- All utilities except buffer.js and kitFile.js
- Menu initializers (
src/menu/*) - Constants (
src/const.js) - Most Electron modules (events, rendererApi except dialog.js and wav.js)
- All SCSS source files (only imports changed, not styles)
Known Issues
Minor DOM nesting warning
Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>.
Location: KitList component has a <div> inside a <p> tag (invalid HTML but doesn't affect functionality).
Verification Checklist
- ✅
npm install- all dependencies resolve - ✅
npm run dev- Vite + Electron start successfully - ✅ App renders without critical errors
- ⏳ Load SD card directory - file dialog opens via IPC
- ⏳ Edit kit pad - rc-slider controls work
- ⏳ Drag sample onto pad - react-dnd works
- ⏳ Preview sample - audio plays
- ⏳
npm run pack- produces macOS .dmg (ARM64 + x64)
Build Output Structure
Development
- Vite dev server runs on http://localhost:5173
- Main process runs unbundled from
electron/main.js - Preload runs unbundled from
electron/preload.js
Production
- Renderer built to
build/directory - Main/preload copied unbundled to package (electron-builder bundles them)
- DMG contains both ARM64 and x64 binaries
Lessons Learned
- Keep it simple: Direct Vite is simpler than electron-vite for this use case
- Module loading timing matters: Be careful about when modules are required in Electron
- Context isolation requires care: electron-store and IPC patterns need main process initialization
- Polyfills can conflict: Better to import explicitly than use global polyfills
- Unbundled main process is fine: No need to bundle main/preload for development
When I tried to pick this project up again it wouldn't start on my Mac. This seemed like the perfect opportunity to see what AI could do to help.
I had a few sessions with Claude to get to grips with this. In the end we reimagined the build process in a more modern way - you can see Claude's summary of what it did.
There were a few things we had to work around, like introducing a new Popover because the old one not longer worked in new versions of Electron and Node.
I have reviewed the diff and believe I've got rid of everything obsolete. I've left the commit structure but we might want to squash when we merge.
I've created Mac (tested fairly well), Windows (it installs and starts, looks like it will work) and Linux (untested) packages as before.
It currently builds a Windows installer - is this correct? Would it be better to just build a standalone tool?