I'm trying to build a vue 3 app, compiled using vite and packaged using electron without any plugins. Here is what I have so far:
Folder structure:
Project
|
+-- electron
| |
| +-- main.js
| +-- preload.js
|
+-- src
| |
| +-- main.js
| +-- App.vue
|
+-- package.json
|
+-- vite.config.js
electron/main.js
import { app, BrowserWindow } from "electron";
import path from "path"
const __dirname = path.resolve();
const createWindow = () => {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(app.getAppPath(), 'preload.js'),
},
});
if (app.isPackaged) {
try {
mainWindow.loadFile('app://./index.html').catch(e => console.log(e));
}
catch (e) {
console.log(e);
}
}
else {
mainWindow.loadURL('http://localhost:3000');
}
};
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
app.whenReady().then(createWindow);
preload.js
window.addEventListener('DOMContentLoaded', () => {
console.log('Preload script loaded');
});
src/main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')
package.json
{
"name": "testme",
"version": "0.0.1",
"description": "demo app",
"scripts": {
"dev": "vite",
"build": "vite build",
"electron:start": "electron electron/main.js",
"start": "vite & electron electron/main.js",
"buildElectron": "npx electron-builder build --mac"
},
"dependencies": {
"vue": "^3.5.10"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.4",
"electron": "^33.0.0-beta.8",
"electron-builder": "^25.1.7",
"vite": "^5.4.8"
},
"main": "electron/main.js",
"type": "module",
"build": {
"appId": "com.ex.me",
"productName": "TEST 1",
"files": [
"dist/**/*",
"electron/**/*",
"preload.js"
],
"directories": {
"buildResources": "assets"
},
"mac": {
"target": [
{
"target": "zip",
"arch": ["x64"]
}
]
}
}
}
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path';
export default defineConfig({
plugins: [vue()],
base: './',
server: {
port: 3000,
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
input: {
main: 'src/main.js',
preload: './electron/preload.js',
},
external: ['electron'],
},
},
});
The app works flawlessly when i run npm start. In other words vite & electron electron/main.js works just fine. But when i run buildElectron, it sucessfully builds the app, but I get two errors:
So it seems that __dirname is causing some problems maybe? As preload.js is not being found. And there seems to be issues with locating or opening index.html when packaged. Anyone have any idea how to debug this? ive tried many many combinations of trying to make preload visible to no avail.
The __dirname
string points to the path of the currently executing script, I'm not sure what yours returns, but usually when using ESM you can get it using either:
import { fileURLToPath } from "url";
import path from "path";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
Or:
import * as url from "url";
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
Then, you should use __dirname
for your preload path instead of app.getAppPath()
:
webPreferences: {
preload: path.join(__dirname, "preload.js")
}
You seem to compile preload
with Vite but not main
, so you may want to use a condition on this path to make sure your main
file when packaged points to the preload
in dist
and not the one you use in dev.
Finally, I'm not sure why you tried to use a custom protocol to load your window file in production, but it's not necessary, the default protocol is enough:
app.isPackaged
? mainWindow.loadFile(path.join(__dirname, "index.html")) // Prod
: mainWindow.loadURL("http://localhost:3000"); // Dev
I don't know the folder structure of your packaged files, so you need to change the prod path accordingly so it points correctly to index.html
.