diff --git a/.gitignore b/.gitignore index 6b05c8e9..709f739c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +squashfs-root +dist-electron +dist-electon-build .DS_Store node_modules /dist diff --git a/package-lock.json b/package-lock.json index e9581899..87a9198d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -97,6 +97,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-vue": "^9.32.0", + "fs-extra": "^11.3.0", "npm-check-updates": "^17.1.13", "postcss": "^8.4.38", "prettier": "^3.2.5", @@ -3755,6 +3756,22 @@ "node": ">= 10.0.0" } }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@electron/osx-sign": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.1.tgz", @@ -3868,21 +3885,6 @@ "node": ">=16.4" } }, - "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -5780,6 +5782,23 @@ "resolve-from": "^5.0.0" } }, + "node_modules/@expo/metro-config/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@expo/metro-config/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -6224,6 +6243,23 @@ "xml2js": "0.6.0" } }, + "node_modules/@expo/prebuild-config/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@expo/prebuild-config/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -6523,6 +6559,21 @@ "node": ">=16.0.0" } }, + "node_modules/@ionic/utils-fs/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@ionic/utils-object": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.5.tgz", @@ -6640,6 +6691,21 @@ "node": ">=10.3.0" } }, + "node_modules/@ionic/utils-subprocess/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@ionic/utils-terminal": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz", @@ -7154,6 +7220,22 @@ "node": ">= 10.0.0" } }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@multiformats/base-x": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@multiformats/base-x/-/base-x-4.0.1.tgz", @@ -15374,6 +15456,22 @@ "node": ">= 10" } }, + "node_modules/expo-modules-autolinking/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/expo-modules-core": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-0.4.10.tgz", @@ -15442,6 +15540,23 @@ "invariant": "^2.2.4" } }, + "node_modules/expo/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/expo/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -16031,18 +16146,18 @@ "peer": true }, "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, "license": "MIT", "dependencies": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=14.14" } }, "node_modules/fs-minipass": { @@ -26813,6 +26928,22 @@ "dev": true, "license": "MIT" }, + "node_modules/workbox-build/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/workbox-build/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", diff --git a/package.json b/package.json index 85145c34..5886f8c4 100644 --- a/package.json +++ b/package.json @@ -112,6 +112,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-vue": "^9.32.0", + "fs-extra": "^11.3.0", "npm-check-updates": "^17.1.13", "postcss": "^8.4.38", "prettier": "^3.2.5", @@ -121,7 +122,7 @@ "vite": "^5.2.0", "vite-plugin-pwa": "^0.19.8" }, - "main": "main.js", + "main": "./dist-electron/main.js", "build": { "appId": "app.timesafari.app", "productName": "TimeSafari", @@ -129,14 +130,18 @@ "output": "dist-electron-build" }, "files": [ + "dist-electron/**/*" + ], + "extraResources": [ { - "from": "dist-electron", - "to": ".", - "filter": ["**/*"] + "from": "dist-electron/www", + "to": "www" } ], "linux": { - "target": ["AppImage"], + "target": [ + "AppImage" + ], "category": "Utility", "icon": "build/icons" }, diff --git a/scripts/build-electron.js b/scripts/build-electron.js index 432d55f6..25c231ff 100644 --- a/scripts/build-electron.js +++ b/scripts/build-electron.js @@ -22,13 +22,27 @@ async function main() { // Copy web files to www directory const wwwDir = path.join(distElectronDir, 'www'); await fs.copy(webDist, wwwDir); - console.log('Copied web files to:', wwwDir); - // Copy and process main.js - const mainJsSrc = path.resolve(__dirname, '../src/electron/main.js'); - const mainJsDest = path.join(distElectronDir, 'main.js'); - await fs.copy(mainJsSrc, mainJsDest); - console.log('Copied main.js to:', mainJsDest); + // Fix paths in index.html + const indexPath = path.join(wwwDir, 'index.html'); + let indexContent = await fs.readFile(indexPath, 'utf8'); + indexContent = indexContent.replace(/src="\//g, 'src="./'); + indexContent = indexContent.replace(/href="\//g, 'href="./'); + indexContent = indexContent.replace(/\/assets\//g, './assets/'); // Fix asset paths with explicit relative path + indexContent = indexContent.replace(/\.\/\.\/assets\//g, './assets/'); // Clean up any double dots + await fs.writeFile(indexPath, indexContent); + + console.log('Copied and fixed web files in:', wwwDir); + + // Copy main process files + const mainProcessFiles = [ + 'src/electron/main.js', + ]; + + for (const file of mainProcessFiles) { + const destPath = path.join(distElectronDir, path.basename(file)); + await fs.copy(file, destPath); + } // Create the production package.json const devPackageJson = require('../package.json'); @@ -38,7 +52,7 @@ async function main() { description: devPackageJson.description, author: devPackageJson.author, main: 'main.js', - private: true + private: true, }; await fs.writeJson( diff --git a/src/electron/main.js b/src/electron/main.js index ac497e3a..ae0f376c 100644 --- a/src/electron/main.js +++ b/src/electron/main.js @@ -1,5 +1,6 @@ const { app, BrowserWindow } = require("electron"); const path = require("path"); +const fs = require("fs"); function createWindow() { // Create the browser window. @@ -9,29 +10,82 @@ function createWindow() { webPreferences: { nodeIntegration: true, contextIsolation: false, + webSecurity: true, + allowRunningInsecureContent: false, }, }); - // Log the paths we're trying to load from - const appPath = app.getAppPath(); - const indexPath = path.join(appPath, "www", "index.html"); + // Disable service worker in Electron + mainWindow.webContents.session.setPermissionRequestHandler( + (webContents, permission, callback) => { + if (permission === "serviceWorker") { + return callback(false); + } + callback(true); + }, + ); + + // Get the correct app path for packaged and development environments + const appPath = app.isPackaged ? process.resourcesPath : app.getAppPath(); + + // Add debug logging for paths + console.log("Debug Info:"); + console.log("App is packaged:", app.isPackaged); + console.log("Process resource path:", process.resourcesPath); console.log("App path:", appPath); - console.log("Trying to load from:", indexPath); - - // Load the index.html file - mainWindow.loadFile(indexPath).catch((err) => { - console.error("Failed to load index.html:", err); - // Try to list directory contents to debug - const fs = require("fs"); - console.log("Directory contents:", fs.readdirSync(appPath)); - }); + console.log("__dirname:", __dirname); + console.log("process.cwd():", process.cwd()); + console.log("www path:", path.join(process.resourcesPath, "www")); + console.log( + "www assets path:", + path.join(process.resourcesPath, "www", "assets"), + ); + + // Try both possible www locations + const possiblePaths = [ + path.join(appPath, "www", "index.html"), + path.join(appPath, "..", "www", "index.html"), + path.join(process.resourcesPath, "www", "index.html"), + ]; - // Open the DevTools in development - if (process.env.NODE_ENV === "development") { - mainWindow.webContents.openDevTools(); + let indexPath; + for (const testPath of possiblePaths) { + console.log("Testing path:", testPath); + if (fs.existsSync(testPath)) { + indexPath = testPath; + console.log("Found valid path:", indexPath); + break; + } } + + // Load the index.html + mainWindow + .loadFile(indexPath) + .then(() => { + console.log("Successfully loaded index.html"); + // Always open DevTools in packaged app for debugging + mainWindow.webContents.openDevTools(); + }) + .catch((err) => { + console.error("Failed to load index.html:", err); + console.error("Attempted path:", indexPath); + }); + + // Listen for page errors + mainWindow.webContents.on( + "did-fail-load", + (event, errorCode, errorDescription) => { + console.error("Page failed to load:", errorCode, errorDescription); + }, + ); + + // Listen for console messages from the renderer + mainWindow.webContents.on("console-message", (_event, level, message) => { + console.log("Renderer Console:", message); + }); } +// Handle app ready app.whenReady().then(() => { createWindow(); @@ -42,6 +96,7 @@ app.whenReady().then(() => { }); }); +// Handle all windows closed app.on("window-all-closed", () => { if (process.platform !== "darwin") { app.quit(); diff --git a/vite.config.mjs b/vite.config.mjs index 5a1ccb0a..a2d75b4c 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -17,7 +17,7 @@ export default defineConfig(({ mode }) => { // Set output directory based on build mode const outDir = isElectron - ? "dist-electron" + ? "dist-electron/www" : isCapacitor ? "dist-capacitor" : "dist"; @@ -32,13 +32,14 @@ export default defineConfig(({ mode }) => { rollupOptions: { ...(isElectron && { input: { - main: path.resolve(__dirname, 'src/electron/main.js'), index: path.resolve(__dirname, 'index.html') }, output: { dir: outDir, format: 'cjs', - entryFileNames: '[name].js' + entryFileNames: 'assets/[name].[hash].js', + chunkFileNames: 'assets/[name].[hash].js', + assetFileNames: 'assets/[name].[hash][extname]' } }) } @@ -46,10 +47,11 @@ export default defineConfig(({ mode }) => { plugins: [ vue(), ...(isElectron - ? [] // Skip PWA for Electron builds + ? [] : [ VitePWA({ ...appConfig.pwaConfig, + disable: isElectron }), ]), ],