forked from trent_larson/crowd-funder-for-time-pwa
refactor: reorganize Vite config into modular files
Split monolithic vite.config.mjs into separate config files: - vite.config.web.mts - vite.config.electron.mts - vite.config.capacitor.mts - vite.config.pywebview.mts - vite.config.common.mts - vite.config.utils.mts Updates: - Modify package.json scripts to use specific config files - Add electron-builder as dev dependency - Update electron build configuration - Fix electron resource paths - Remove old vite.config.mjs and utils.js This change improves maintainability by: - Separating concerns for different build targets - Making build configurations more explicit - Reducing complexity in individual config files
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -38,4 +38,5 @@ pnpm-debug.log*
|
||||
/dist-capacitor/
|
||||
/test-playwright-results/
|
||||
playwright-tests
|
||||
test-playwright
|
||||
test-playwright
|
||||
dist-electron-packages
|
||||
29
main.js
Normal file
29
main.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const { app, BrowserWindow } = require('electron');
|
||||
const path = require('path');
|
||||
|
||||
function createWindow() {
|
||||
const win = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 800,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
}
|
||||
});
|
||||
|
||||
win.loadFile(path.join(__dirname, 'dist-electron/www/index.html'));
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow);
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
2591
package-lock.json
generated
2591
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@@ -15,20 +15,21 @@
|
||||
"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",
|
||||
"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",
|
||||
"build:pywebview": "vite build --config vite.config.pywebview.mts",
|
||||
"build:electron": "npm run clean:electron && vite build --config vite.config.electron.mts && node scripts/build-electron.js",
|
||||
"build:capacitor": "vite build --config vite.config.capacitor.mts",
|
||||
"build:web": "vite build --config vite.config.web.mts",
|
||||
"electron:dev": "npm run build && electron dist-electron",
|
||||
"electron:start": "electron dist-electron",
|
||||
"electron:build-linux": "electron-builder --linux AppImage",
|
||||
"electron:build-linux-deb": "electron-builder --linux deb",
|
||||
"electron:build-linux": "npm run build:electron && electron-builder --linux AppImage",
|
||||
"electron:build-linux-deb": "npm run build:electron && electron-builder --linux deb",
|
||||
"electron:build-linux-prod": "NODE_ENV=production npm run build:electron && electron-builder --linux AppImage",
|
||||
"build:electron-prod": "NODE_ENV=production npm run build:electron",
|
||||
"electron:build-linux-prod": "npm run build:electron-prod && electron-builder --linux AppImage",
|
||||
"pywebview:dev": "vite build --mode pywebview && .venv/bin/python src/pywebview/main.py",
|
||||
"pywebview:build": "vite build --mode pywebview && .venv/bin/python src/pywebview/main.py",
|
||||
"pywebview:package-linux": "vite build --mode pywebview && .venv/bin/python -m PyInstaller --name TimeSafari --add-data 'dist:www' src/pywebview/main.py",
|
||||
"pywebview:package-win": "vite build --mode pywebview && .venv/Scripts/python -m PyInstaller --name TimeSafari --add-data 'dist;www' src/pywebview/main.py",
|
||||
"pywebview:package-mac": "vite build --mode pywebview && .venv/bin/python -m PyInstaller --name TimeSafari --add-data 'dist:www' src/pywebview/main.py"
|
||||
"pywebview:dev": "vite build --config vite.config.pywebview.mts && .venv/bin/python src/pywebview/main.py",
|
||||
"pywebview:build": "vite build --config vite.config.pywebview.mts && .venv/bin/python src/pywebview/main.py",
|
||||
"pywebview:package-linux": "vite build --mode pywebview --config vite.config.pywebview.mts && .venv/bin/python -m PyInstaller --name TimeSafari --add-data 'dist:www' src/pywebview/main.py",
|
||||
"pywebview:package-win": "vite build --mode pywebview --config vite.config.pywebview.mts && .venv/Scripts/python -m PyInstaller --name TimeSafari --add-data 'dist;www' src/pywebview/main.py",
|
||||
"pywebview:package-mac": "vite build --mode pywebview --config vite.config.pywebview.mts && .venv/bin/python -m PyInstaller --name TimeSafari --add-data 'dist:www' src/pywebview/main.py"
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor/android": "^6.2.0",
|
||||
@@ -116,6 +117,7 @@
|
||||
"autoprefixer": "^10.4.19",
|
||||
"concurrently": "^8.2.2",
|
||||
"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",
|
||||
@@ -139,12 +141,13 @@
|
||||
},
|
||||
"files": [
|
||||
"dist-electron/**/*",
|
||||
"src/electron/**/*"
|
||||
"src/electron/**/*",
|
||||
"main.js"
|
||||
],
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "dist-electron/www",
|
||||
"to": "www"
|
||||
"from": "dist-electron",
|
||||
"to": "."
|
||||
}
|
||||
],
|
||||
"linux": {
|
||||
|
||||
16
src/main.capacitor.ts
Normal file
16
src/main.capacitor.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { initializeApp } from "./main.common";
|
||||
import { App } from "@capacitor/app";
|
||||
import router from "./router";
|
||||
|
||||
const app = initializeApp();
|
||||
|
||||
// Handle deep links
|
||||
App.addListener("appUrlOpen", (data: { url: string }) => {
|
||||
console.log("Deep link opened:", data.url);
|
||||
const slug = data.url.replace("timesafari://", "");
|
||||
if (slug) {
|
||||
router.push("/" + slug);
|
||||
}
|
||||
});
|
||||
|
||||
app.mount("#app");
|
||||
40
src/main.common.ts
Normal file
40
src/main.common.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { createPinia } from "pinia";
|
||||
import { App as VueApp, ComponentPublicInstance, createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import axios from "axios";
|
||||
import VueAxios from "vue-axios";
|
||||
import Notifications from "notiwind";
|
||||
import "./assets/styles/tailwind.css";
|
||||
import { FontAwesomeIcon } from "./lib/fontawesome";
|
||||
import Camera from "simple-vue-camera";
|
||||
|
||||
// Global Error Handler
|
||||
function setupGlobalErrorHandler(app: VueApp) {
|
||||
app.config.errorHandler = (
|
||||
err: unknown,
|
||||
instance: ComponentPublicInstance | null,
|
||||
info: string
|
||||
) => {
|
||||
console.error("Ouch! Global Error Handler.", err, info, instance);
|
||||
alert(
|
||||
(err instanceof Error ? err.message : "Something bad happened") +
|
||||
" - Try reloading or restarting the app."
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// Function to initialize the app
|
||||
export function initializeApp() {
|
||||
const app = createApp(App)
|
||||
.component("fa", FontAwesomeIcon)
|
||||
.component("camera", Camera)
|
||||
.use(createPinia())
|
||||
.use(VueAxios, axios)
|
||||
.use(router)
|
||||
.use(Notifications);
|
||||
|
||||
setupGlobalErrorHandler(app);
|
||||
|
||||
return app;
|
||||
}
|
||||
5
src/main.web.ts
Normal file
5
src/main.web.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { initializeApp } from "./main.common";
|
||||
import "./registerServiceWorker"; // Web PWA support
|
||||
|
||||
const app = initializeApp();
|
||||
app.mount("#app");
|
||||
4
vite.config.capacitor.mts
Normal file
4
vite.config.capacitor.mts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { createBuildConfig } from "./vite.config.common.mts";
|
||||
|
||||
export default defineConfig(async () => createBuildConfig('capacitor'));
|
||||
55
vite.config.common.mts
Normal file
55
vite.config.common.mts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import dotenv from "dotenv";
|
||||
import { loadAppConfig } from "./vite.config.utils.mts";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// Load environment variables
|
||||
dotenv.config();
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export async function createBuildConfig(mode: string) {
|
||||
const appConfig = await loadAppConfig();
|
||||
const isElectron = mode === "electron";
|
||||
const isCapacitor = mode === "capacitor";
|
||||
const isPyWebView = mode === "pywebview";
|
||||
|
||||
if (isElectron || isPyWebView) {
|
||||
process.env.VITE_PWA_ENABLED = 'false';
|
||||
}
|
||||
|
||||
return {
|
||||
base: isElectron || isPyWebView ? "./" : "/",
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: parseInt(process.env.VITE_PORT || "8080"),
|
||||
fs: { strict: false },
|
||||
},
|
||||
build: {
|
||||
outDir: isElectron ? "dist-electron" : "dist",
|
||||
assetsDir: 'assets',
|
||||
chunkSizeWarningLimit: 1000
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
'process.env.VITE_PWA_ENABLED': JSON.stringify(!(isElectron || isPyWebView)),
|
||||
__dirname: isElectron ? JSON.stringify(process.cwd()) : '""',
|
||||
},
|
||||
resolve: {
|
||||
alias: appConfig.aliasConfig
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: isElectron ? [
|
||||
'register-service-worker',
|
||||
'workbox-window',
|
||||
'web-push',
|
||||
'serviceworker-webpack-plugin'
|
||||
] : []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig(async () => createBuildConfig('web'));
|
||||
29
vite.config.electron.mts
Normal file
29
vite.config.electron.mts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { defineConfig, mergeConfig } from "vite";
|
||||
import { createBuildConfig } from "./vite.config.common.mts";
|
||||
|
||||
export default defineConfig(async () => {
|
||||
const baseConfig = await createBuildConfig('electron');
|
||||
|
||||
return mergeConfig(baseConfig, {
|
||||
plugins: [{
|
||||
name: 'remove-sw-imports',
|
||||
transform(code: string, id: string) {
|
||||
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, '')
|
||||
};
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
});
|
||||
120
vite.config.mjs
120
vite.config.mjs
@@ -1,120 +0,0 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
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();
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const isElectron = mode === "electron";
|
||||
const isCapacitor = mode === "capacitor";
|
||||
const isPyWebView = mode === "pywebview";
|
||||
|
||||
// Disable PWA features for desktop builds
|
||||
if (isElectron || isPyWebView) {
|
||||
process.env.VITE_PWA_ENABLED = 'false';
|
||||
}
|
||||
|
||||
return {
|
||||
base: isElectron || isPyWebView ? "./" : "/",
|
||||
server: {
|
||||
port: process.env.VITE_PORT || 8080,
|
||||
fs: {
|
||||
strict: false
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: isElectron ? "dist-electron" : "dist",
|
||||
assetsDir: 'assets',
|
||||
rollupOptions: {
|
||||
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 || isPyWebView)),
|
||||
__dirname: isElectron ? JSON.stringify(process.cwd()) : '""',
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
{
|
||||
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
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: isElectron ? [
|
||||
'register-service-worker',
|
||||
'workbox-window',
|
||||
'web-push',
|
||||
'serviceworker-webpack-plugin'
|
||||
] : []
|
||||
}
|
||||
};
|
||||
});
|
||||
4
vite.config.pywebview.mts
Normal file
4
vite.config.pywebview.mts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { createBuildConfig } from "./vite.config.common.mts";
|
||||
|
||||
export default defineConfig(async () => createBuildConfig('pywebview'));
|
||||
@@ -1,7 +1,57 @@
|
||||
import * as path from "path";
|
||||
import { fileURLToPath } from 'url';
|
||||
import { promises as fs } from "fs";
|
||||
|
||||
export async function loadAppConfig() {
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
async function loadPackageJson() {
|
||||
const packageJsonPath = path.join(__dirname, 'package.json');
|
||||
const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
|
||||
return JSON.parse(packageJsonContent);
|
||||
}
|
||||
|
||||
interface ManifestIcon {
|
||||
src: string;
|
||||
sizes: string;
|
||||
type: string;
|
||||
purpose?: string;
|
||||
}
|
||||
|
||||
interface ShareTarget {
|
||||
action: string;
|
||||
method: "POST";
|
||||
enctype: string;
|
||||
params: {
|
||||
files: Array<{
|
||||
name: string;
|
||||
accept: string[];
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
interface PWAConfig {
|
||||
registerType: string;
|
||||
strategies: string;
|
||||
srcDir: string;
|
||||
filename: string;
|
||||
manifest: {
|
||||
name: string;
|
||||
short_name: string;
|
||||
theme_color: string;
|
||||
background_color: string;
|
||||
icons: ManifestIcon[];
|
||||
share_target: ShareTarget;
|
||||
};
|
||||
}
|
||||
|
||||
interface AppConfig {
|
||||
pwaConfig: PWAConfig;
|
||||
aliasConfig: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadAppConfig(): Promise<AppConfig> {
|
||||
const packageJson = await loadPackageJson();
|
||||
const appName = process.env.TIME_SAFARI_APP_TITLE || packageJson.name;
|
||||
|
||||
@@ -14,6 +64,8 @@ export async function loadAppConfig() {
|
||||
manifest: {
|
||||
name: appName,
|
||||
short_name: appName,
|
||||
theme_color: "#4a90e2",
|
||||
background_color: "#ffffff",
|
||||
icons: [
|
||||
{
|
||||
src: "./img/icons/android-chrome-192x192.png",
|
||||
@@ -54,16 +106,10 @@ export async function loadAppConfig() {
|
||||
},
|
||||
},
|
||||
aliasConfig: {
|
||||
"@": path.resolve(__dirname, ".."),
|
||||
"@": path.resolve(__dirname, "src"),
|
||||
buffer: path.resolve(__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 packageJsonData = await fs.readFile(packageJsonPath, "utf-8");
|
||||
return JSON.parse(packageJsonData);
|
||||
}
|
||||
}
|
||||
27
vite.config.web.mts
Normal file
27
vite.config.web.mts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineConfig, mergeConfig } from "vite";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
import { createBuildConfig } from "./vite.config.common.mts";
|
||||
import { loadAppConfig } from "./vite.config.utils.mts";
|
||||
|
||||
export default defineConfig(async () => {
|
||||
const baseConfig = await createBuildConfig('web');
|
||||
const appConfig = await loadAppConfig();
|
||||
|
||||
return mergeConfig(baseConfig, {
|
||||
plugins: [
|
||||
VitePWA({
|
||||
registerType: 'autoUpdate',
|
||||
manifest: appConfig.pwaConfig?.manifest,
|
||||
devOptions: {
|
||||
enabled: false
|
||||
},
|
||||
workbox: {
|
||||
cleanupOutdatedCaches: true,
|
||||
skipWaiting: true,
|
||||
clientsClaim: true,
|
||||
sourcemap: true
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user