forked from trent_larson/crowd-funder-for-time-pwa
WIP (fix): improve electron build configuration and service worker handling
- Properly disable service workers in electron builds - Add CSP headers for electron security - Fix path resolution in electron context - Improve preload script error handling and IPC setup - Update build scripts for better electron/capacitor compatibility - Fix router path handling in electron context - Remove electron-builder dependency - Streamline build process and output structure This change improves the stability and security of electron builds while maintaining PWA functionality in web builds. Service workers are now properly disabled in electron context, and path resolution issues are fixed.
This commit is contained in:
11
BUILDING.md
11
BUILDING.md
@@ -46,21 +46,16 @@ To build the desktop application:
|
||||
|
||||
1. Run the Electron build:
|
||||
```bash
|
||||
npm run build -- --mode electron
|
||||
npm run build:electron
|
||||
```
|
||||
|
||||
2. The built files will be in `dist-electron`.
|
||||
|
||||
3. To create installable packages:
|
||||
3. To run the desktop app:
|
||||
```bash
|
||||
npm run electron:build
|
||||
electron dist-electron
|
||||
```
|
||||
|
||||
This will create platform-specific installers in `dist-electron-build`:
|
||||
- Windows: `.exe` installer
|
||||
- macOS: `.dmg` file
|
||||
- Linux: `.AppImage` file
|
||||
|
||||
## Mobile Builds (Capacitor)
|
||||
|
||||
### iOS Build
|
||||
|
||||
2591
package-lock.json
generated
2591
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,13 +14,12 @@
|
||||
"prebuild": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src && node sw_combine.js",
|
||||
"test-local": "npx playwright test -c playwright.config-local.ts --trace on",
|
||||
"test-all": "npm run build && npx playwright test -c playwright.config-local.ts --trace on",
|
||||
"clean:electron": "rimraf dist-electron dist-electron-build",
|
||||
"clean:electron": "rimraf dist-electron",
|
||||
"build:electron": "npm run clean:electron && vite build --mode electron && node scripts/build-electron.js",
|
||||
"build:capacitor": "vite build --mode capacitor",
|
||||
"build:web": "vite build",
|
||||
"electron:build:linux": "npm run build:electron && electron-builder --linux",
|
||||
"electron:build:mac": "npm run build:electron && npx electron-builder --mac",
|
||||
"electron:build:win": "npm run build:electron && npx electron-builder --win"
|
||||
"electron:dev": "npm run build:electron && electron dist-electron --inspect",
|
||||
"electron:start": "electron dist-electron"
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor/android": "^6.2.0",
|
||||
@@ -107,7 +106,6 @@
|
||||
"@vue/eslint-config-typescript": "^11.0.3",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"electron": "^33.2.1",
|
||||
"electron-builder": "^25.1.8",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
|
||||
@@ -1,61 +1,48 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('Starting electron build process...');
|
||||
|
||||
// Clean directories
|
||||
|
||||
// Create dist directory if it doesn't exist
|
||||
const distElectronDir = path.resolve(__dirname, '../dist-electron');
|
||||
const buildDir = path.resolve(__dirname, '../dist-electron-build');
|
||||
await fs.emptyDir(distElectronDir);
|
||||
await fs.emptyDir(buildDir);
|
||||
console.log('Cleaned directories');
|
||||
await fs.ensureDir(distElectronDir);
|
||||
|
||||
// First build the web app if it doesn't exist
|
||||
const webDist = path.resolve(__dirname, '../dist');
|
||||
if (!await fs.pathExists(webDist)) {
|
||||
console.log('Web dist not found, building web app first...');
|
||||
throw new Error('Please run \'npm run build\' first to build the web app');
|
||||
}
|
||||
|
||||
// Copy web files to www directory
|
||||
// Copy web files
|
||||
const wwwDir = path.join(distElectronDir, 'www');
|
||||
await fs.copy(webDist, wwwDir);
|
||||
await fs.ensureDir(wwwDir);
|
||||
await fs.copy('dist', wwwDir);
|
||||
|
||||
// Fix paths in index.html
|
||||
// Copy and fix index.html
|
||||
const indexPath = path.join(wwwDir, 'index.html');
|
||||
let indexContent = await fs.readFile(indexPath, 'utf8');
|
||||
|
||||
// Fix paths in index.html
|
||||
indexContent = indexContent
|
||||
// Fix absolute paths to be relative
|
||||
.replace(/src="\//g, 'src="\./')
|
||||
.replace(/href="\//g, 'href="\./')
|
||||
// Fix relative asset paths
|
||||
.replace(/src="\.\.\/assets\//g, 'src="./www/assets/')
|
||||
.replace(/href="\.\.\/assets\//g, 'href="./www/assets/')
|
||||
// Fix modulepreload paths specifically
|
||||
.replace(/<link [^>]*rel="modulepreload"[^>]*href="(?!\.?\/www\/)(\/\.\/)?assets\//g, '<link rel="modulepreload" as="script" crossorigin="" href="./www/assets/')
|
||||
.replace(/<link [^>]*rel="modulepreload"[^>]*href="(?!\.?\/www\/)(\/)?assets\//g, '<link rel="modulepreload" as="script" crossorigin="" href="./www/assets/')
|
||||
// Fix stylesheet paths
|
||||
.replace(/<link [^>]*rel="stylesheet"[^>]*href="(?!\.?\/www\/)(\/\.\/)?assets\//g, '<link rel="stylesheet" crossorigin="" href="./www/assets/')
|
||||
.replace(/<link [^>]*rel="stylesheet"[^>]*href="(?!\.?\/www\/)(\/)?assets\//g, '<link rel="stylesheet" crossorigin="" href="./www/assets/')
|
||||
// Fix any remaining asset paths that don't already have www
|
||||
.replace(/(['"]\/?)((?!www\/)(assets\/))/, '"./www/assets/');
|
||||
.replace(/href="\.\.\/assets\//g, 'href="./www/assets/');
|
||||
|
||||
await fs.writeFile(indexPath, indexContent);
|
||||
|
||||
console.log('Copied and fixed web files in:', wwwDir);
|
||||
|
||||
// Copy main process files
|
||||
console.log('Copying main process files...');
|
||||
const mainProcessFiles = [
|
||||
'src/electron/main.js',
|
||||
['src/electron/main.js', 'main.js'],
|
||||
['src/electron/preload.js', 'preload.js']
|
||||
];
|
||||
|
||||
for (const file of mainProcessFiles) {
|
||||
const destPath = path.join(distElectronDir, path.basename(file));
|
||||
await fs.copy(file, destPath);
|
||||
for (const [src, dest] of mainProcessFiles) {
|
||||
const destPath = path.join(distElectronDir, dest);
|
||||
console.log(`Copying ${src} to ${destPath}`);
|
||||
await fs.copy(src, destPath);
|
||||
}
|
||||
|
||||
// Create the production package.json
|
||||
// Create package.json for production
|
||||
const devPackageJson = require('../package.json');
|
||||
const prodPackageJson = {
|
||||
name: devPackageJson.name,
|
||||
@@ -72,26 +59,26 @@ async function main() {
|
||||
{ spaces: 2 }
|
||||
);
|
||||
|
||||
// Verify the structure
|
||||
// Verify the build
|
||||
console.log('\nVerifying build structure:');
|
||||
const printDir = async (dir, prefix = '') => {
|
||||
const items = await fs.readdir(dir);
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(dir, item);
|
||||
const stat = await fs.stat(fullPath);
|
||||
console.log(`${prefix}${item}${stat.isDirectory() ? '/' : ''}`);
|
||||
if (stat.isDirectory()) {
|
||||
await printDir(fullPath, `${prefix} `);
|
||||
}
|
||||
}
|
||||
};
|
||||
await printDir(distElectronDir);
|
||||
const files = await fs.readdir(distElectronDir);
|
||||
console.log('Files in dist-electron:', files);
|
||||
|
||||
console.log('\nBuild completed successfully!');
|
||||
if (!files.includes('main.js')) {
|
||||
throw new Error('main.js not found in build directory');
|
||||
}
|
||||
if (!files.includes('preload.js')) {
|
||||
throw new Error('preload.js not found in build directory');
|
||||
}
|
||||
if (!files.includes('package.json')) {
|
||||
throw new Error('package.json not found in build directory');
|
||||
}
|
||||
|
||||
console.log('Build completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('Build failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main();
|
||||
@@ -2,99 +2,103 @@ const { app, BrowserWindow } = require("electron");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
// Check if running in dev mode
|
||||
const isDev = process.argv.includes('--inspect');
|
||||
|
||||
function createWindow() {
|
||||
// Add before createWindow function
|
||||
const preloadPath = path.join(__dirname, 'preload.js');
|
||||
console.log('Checking preload path:', preloadPath);
|
||||
console.log('Preload exists:', fs.existsSync(preloadPath));
|
||||
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 800,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
webSecurity: true,
|
||||
allowRunningInsecureContent: false,
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
},
|
||||
});
|
||||
|
||||
// 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
|
||||
// Debug info
|
||||
console.log("Debug Info:");
|
||||
console.log("Running in dev mode:", isDev);
|
||||
console.log("App is packaged:", app.isPackaged);
|
||||
console.log("Process resource path:", process.resourcesPath);
|
||||
console.log("App path:", appPath);
|
||||
console.log("App path:", app.getAppPath());
|
||||
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"),
|
||||
];
|
||||
const indexPath = path.join(__dirname, 'www', 'index.html');
|
||||
console.log("www path:", path.join(__dirname, 'www'));
|
||||
console.log("www assets path:", path.join(__dirname, 'www', 'assets'));
|
||||
|
||||
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;
|
||||
}
|
||||
if (!fs.existsSync(indexPath)) {
|
||||
console.error(`Index file not found at: ${indexPath}`);
|
||||
throw new Error('Index file not found');
|
||||
}
|
||||
|
||||
// Set CSP headers
|
||||
mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
|
||||
callback({
|
||||
responseHeaders: {
|
||||
...details.responseHeaders,
|
||||
'Content-Security-Policy': [
|
||||
"default-src 'self';" +
|
||||
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;" +
|
||||
"font-src 'self' https://fonts.gstatic.com;" +
|
||||
"script-src 'self' 'unsafe-eval' 'unsafe-inline';" +
|
||||
"img-src 'self' data: https:;"
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 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();
|
||||
if (isDev) {
|
||||
mainWindow.webContents.openDevTools();
|
||||
console.log("DevTools opened - running in dev mode");
|
||||
}
|
||||
})
|
||||
.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);
|
||||
});
|
||||
|
||||
// Add right after creating the BrowserWindow
|
||||
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
|
||||
console.error('Page failed to load:', errorCode, errorDescription);
|
||||
});
|
||||
|
||||
mainWindow.webContents.on('preload-error', (event, preloadPath, error) => {
|
||||
console.error('Preload script error:', preloadPath, error);
|
||||
});
|
||||
|
||||
mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => {
|
||||
console.log('Renderer Console:', message);
|
||||
});
|
||||
|
||||
// Enable remote debugging when in dev mode
|
||||
if (isDev) {
|
||||
mainWindow.webContents.openDevTools();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle app ready
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
|
||||
app.on("activate", () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
app.whenReady().then(createWindow);
|
||||
|
||||
// Handle all windows closed
|
||||
app.on("window-all-closed", () => {
|
||||
@@ -103,6 +107,12 @@ app.on("window-all-closed", () => {
|
||||
}
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle any errors
|
||||
process.on("uncaughtException", (error) => {
|
||||
console.error("Uncaught Exception:", error);
|
||||
|
||||
@@ -1,5 +1,55 @@
|
||||
const { contextBridge } = require("electron");
|
||||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
contextBridge.exposeInMainWorld("api", {
|
||||
logMessage: (message) => console.log(`[Electron]: ${message}`),
|
||||
});
|
||||
// Use a more direct path resolution approach
|
||||
const getPath = (pathType) => {
|
||||
switch(pathType) {
|
||||
case 'userData':
|
||||
return process.env.APPDATA || (
|
||||
process.platform === 'darwin'
|
||||
? `${process.env.HOME}/Library/Application Support`
|
||||
: `${process.env.HOME}/.local/share`
|
||||
);
|
||||
case 'home':
|
||||
return process.env.HOME;
|
||||
case 'appPath':
|
||||
return process.resourcesPath;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
console.log('Preload script starting...');
|
||||
|
||||
try {
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
// Path utilities
|
||||
getPath,
|
||||
|
||||
// IPC functions
|
||||
send: (channel, data) => {
|
||||
const validChannels = ['toMain'];
|
||||
if (validChannels.includes(channel)) {
|
||||
ipcRenderer.send(channel, data);
|
||||
}
|
||||
},
|
||||
receive: (channel, func) => {
|
||||
const validChannels = ['fromMain'];
|
||||
if (validChannels.includes(channel)) {
|
||||
ipcRenderer.on(channel, (event, ...args) => func(...args));
|
||||
}
|
||||
},
|
||||
// Environment info
|
||||
env: {
|
||||
isElectron: true,
|
||||
isDev: process.env.NODE_ENV === 'development'
|
||||
},
|
||||
// Path utilities
|
||||
getBasePath: () => {
|
||||
return process.env.NODE_ENV === 'development' ? '/' : './';
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Preload script completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Error in preload script:', error);
|
||||
}
|
||||
@@ -2,14 +2,11 @@
|
||||
|
||||
import { register } from "register-service-worker";
|
||||
|
||||
// NODE_ENV is "production" by default with "vite build". See https://vitejs.dev/guide/env-and-mode
|
||||
if (import.meta.env.NODE_ENV === "production") {
|
||||
register("/sw_scripts-combined.js", {
|
||||
// Only register service worker if explicitly enabled and in production
|
||||
if (process.env.VITE_PWA_ENABLED === 'true' && process.env.NODE_ENV === "production") {
|
||||
register(`${process.env.BASE_URL}sw.js`, {
|
||||
ready() {
|
||||
console.log(
|
||||
"App is being served from cache by a service worker.\n" +
|
||||
"For more details, visit https://goo.gl/AFskqB",
|
||||
);
|
||||
console.log("Service worker is active.");
|
||||
},
|
||||
registered() {
|
||||
console.log("Service worker has been registered.");
|
||||
@@ -24,12 +21,12 @@ if (import.meta.env.NODE_ENV === "production") {
|
||||
console.log("New content is available; please refresh.");
|
||||
},
|
||||
offline() {
|
||||
console.log(
|
||||
"No internet connection found. App is running in offline mode.",
|
||||
);
|
||||
console.log("No internet connection found. App is running in offline mode.");
|
||||
},
|
||||
error(error) {
|
||||
console.error("Error during service worker registration:", error);
|
||||
},
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log("Service worker registration skipped - not enabled or not in production");
|
||||
}
|
||||
|
||||
@@ -284,9 +284,9 @@ const routes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
];
|
||||
|
||||
const isElectron = window.location.protocol === "file:"; // Check if running in Electron
|
||||
const isElectron = window.location.protocol === "file:";
|
||||
const initialPath = isElectron
|
||||
? window.location.pathname.replace("/dist-electron/index.html", "/")
|
||||
? window.location.pathname.split('/dist-electron/www/')[1] || '/'
|
||||
: window.location.pathname;
|
||||
|
||||
const history = isElectron
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import * as path from "path";
|
||||
import { promises as fs } from "fs";
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
export async function loadAppConfig() {
|
||||
const packageJson = await loadPackageJson();
|
||||
const appName = process.env.TIME_SAFARI_APP_TITLE || packageJson.name;
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
return {
|
||||
pwaConfig: {
|
||||
registerType: "autoUpdate",
|
||||
strategies: "injectManifest",
|
||||
srcDir: ".",
|
||||
filename: "sw_scripts-combined.js",
|
||||
manifest: {
|
||||
name: appName,
|
||||
short_name: appName,
|
||||
@@ -36,34 +34,21 @@ export async function loadAppConfig() {
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "maskable",
|
||||
},
|
||||
],
|
||||
share_target: {
|
||||
action: "/share-target",
|
||||
method: "POST",
|
||||
enctype: "multipart/form-data",
|
||||
params: {
|
||||
files: [
|
||||
{
|
||||
name: "photo",
|
||||
accept: ["image/*"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
aliasConfig: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
buffer: path.resolve(__dirname, "node_modules", "buffer"),
|
||||
"dexie-export-import/dist/import":
|
||||
"dexie-export-import/dist/import/index.js",
|
||||
},
|
||||
"@": path.resolve(path.dirname(__dirname), "src"),
|
||||
buffer: path.resolve(path.dirname(__dirname), "node_modules", "buffer"),
|
||||
"dexie-export-import/dist/import": "dexie-export-import/dist/import/index.js",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function loadPackageJson() {
|
||||
const packageJsonPath = path.resolve(__dirname, "package.json");
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const packageJsonPath = path.resolve(path.dirname(__dirname), "package.json");
|
||||
const packageJsonData = await fs.readFile(packageJsonPath, "utf-8");
|
||||
return JSON.parse(packageJsonData);
|
||||
}
|
||||
|
||||
114
vite.config.mjs
114
vite.config.mjs
@@ -4,10 +4,15 @@ import vue from "@vitejs/plugin-vue";
|
||||
import dotenv from "dotenv";
|
||||
import { loadAppConfig } from "./vite.config.utils";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// Load environment variables from .env file
|
||||
dotenv.config();
|
||||
|
||||
// Get dirname in ESM context
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Load application configuration
|
||||
const appConfig = loadAppConfig();
|
||||
|
||||
@@ -15,48 +20,101 @@ export default defineConfig(({ mode }) => {
|
||||
const isElectron = mode === "electron";
|
||||
const isCapacitor = mode === "capacitor";
|
||||
|
||||
// Set output directory based on build mode
|
||||
const outDir = isElectron
|
||||
? "dist-electron/www"
|
||||
: isCapacitor
|
||||
? "dist-capacitor"
|
||||
: "dist";
|
||||
// Completely disable PWA features for electron builds
|
||||
if (isElectron) {
|
||||
process.env.VITE_PWA_ENABLED = 'false';
|
||||
}
|
||||
|
||||
return {
|
||||
base: isElectron ? "./" : "/",
|
||||
server: {
|
||||
port: process.env.VITE_PORT || 8080,
|
||||
fs: {
|
||||
strict: false
|
||||
}
|
||||
},
|
||||
build: {
|
||||
outDir,
|
||||
outDir: isElectron ? "dist-electron" : "dist",
|
||||
assetsDir: 'assets',
|
||||
rollupOptions: {
|
||||
...(isElectron && {
|
||||
input: {
|
||||
index: path.resolve(__dirname, 'index.html')
|
||||
},
|
||||
output: {
|
||||
dir: outDir,
|
||||
format: 'cjs',
|
||||
entryFileNames: 'assets/[name].[hash].js',
|
||||
chunkFileNames: 'assets/[name].[hash].js',
|
||||
assetFileNames: 'assets/[name].[hash][extname]'
|
||||
external: ['electron', 'path'],
|
||||
input: {
|
||||
main: path.resolve(__dirname, 'index.html')
|
||||
},
|
||||
output: {
|
||||
manualChunks(id) {
|
||||
if (isElectron && (
|
||||
id.includes('registerServiceWorker') ||
|
||||
id.includes('register-service-worker') ||
|
||||
id.includes('workbox') ||
|
||||
id.includes('sw_scripts') ||
|
||||
id.includes('PushNotificationPermission')
|
||||
)) {
|
||||
return null; // Exclude these modules completely
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
chunkSizeWarningLimit: 1000
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
'process.env.VITE_PWA_ENABLED': JSON.stringify(!isElectron),
|
||||
__dirname: isElectron ? JSON.stringify(process.cwd()) : '""',
|
||||
'navigator.serviceWorker': isElectron ? 'undefined' : 'navigator.serviceWorker'
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
...(isElectron
|
||||
? []
|
||||
: [
|
||||
VitePWA({
|
||||
...appConfig.pwaConfig,
|
||||
disable: isElectron
|
||||
}),
|
||||
]),
|
||||
{
|
||||
name: 'remove-sw-imports',
|
||||
transform(code, id) {
|
||||
if (isElectron) {
|
||||
if (
|
||||
id.includes('registerServiceWorker') ||
|
||||
id.includes('register-service-worker') ||
|
||||
id.includes('sw_scripts') ||
|
||||
id.includes('PushNotificationPermission') ||
|
||||
code.includes('navigator.serviceWorker')
|
||||
) {
|
||||
return {
|
||||
code: code
|
||||
.replace(/import.*registerServiceWorker.*$/mg, '')
|
||||
.replace(/import.*register-service-worker.*$/mg, '')
|
||||
.replace(/navigator\.serviceWorker/g, 'undefined')
|
||||
.replace(/if\s*\([^)]*serviceWorker[^)]*\)\s*{[^}]*}/g, '')
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
...(!isElectron && !isCapacitor ? [
|
||||
VitePWA({
|
||||
disable: true,
|
||||
registerType: 'autoUpdate',
|
||||
injectRegister: null,
|
||||
workbox: {
|
||||
cleanupOutdatedCaches: true,
|
||||
skipWaiting: true,
|
||||
clientsClaim: true,
|
||||
sourcemap: true
|
||||
},
|
||||
manifest: appConfig.pwaConfig?.manifest,
|
||||
devOptions: {
|
||||
enabled: false
|
||||
}
|
||||
}),
|
||||
] : []),
|
||||
],
|
||||
resolve: {
|
||||
alias: appConfig.aliasConfig,
|
||||
alias: appConfig.aliasConfig
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: isElectron ? [
|
||||
'register-service-worker',
|
||||
'workbox-window',
|
||||
'web-push',
|
||||
'serviceworker-webpack-plugin'
|
||||
] : []
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user