forked from trent_larson/crowd-funder-for-time-pwa
docs: move build instructions from README to BUILDING.md
- Move detailed setup and build instructions from README.md to BUILDING.md - Add concise reference to BUILDING.md in README.md - Keep testing and other documentation in README.md - Improve organization of documentation by separating build-specific content
This commit is contained in:
74
README.md
74
README.md
@@ -8,79 +8,9 @@ and expand to crowd-fund with time & money, then record and see the impact of co
|
||||
See [project.task.yaml](project.task.yaml) for current priorities.
|
||||
(Numbers at the beginning of lines are estimated hours. See [taskyaml.org](https://taskyaml.org/) for details.)
|
||||
|
||||
## Setup
|
||||
|
||||
We like pkgx: `sh <(curl https://pkgx.sh) +vite sh`
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and hot-reloads for development
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
See the test locations for "IMAGE_API_SERVER" or "PARTNER_API_SERVER" below, or use http://localhost:3000 for local endorser.ch
|
||||
|
||||
### Build the test & production app
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Lint and fix files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Run all UI tests
|
||||
|
||||
Look below for the "test-all" instructions.
|
||||
|
||||
|
||||
### Compile and minify for test & production
|
||||
|
||||
* If there are DB changes: before updating the test server, open browser(s) with current version to test DB migrations.
|
||||
|
||||
* `npx prettier --write ./sw_scripts/`
|
||||
|
||||
* Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run `npm install`.
|
||||
|
||||
* Commit everything (since the commit hash is used the app).
|
||||
|
||||
* Put the commit hash in the changelog (which will help you remember to bump the version later).
|
||||
|
||||
* Tag with the new version, [online](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) or `git tag 0.3.36` && `git push origin 0.3.36`.
|
||||
|
||||
* For test, build the app (because test server is not yet set up to build):
|
||||
|
||||
```
|
||||
TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.app VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch VITE_PASSKEYS_ENABLED=true npm run build
|
||||
```
|
||||
|
||||
... and transfer to the test server: `rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntutest@test.timesafari.app:time-safari`
|
||||
|
||||
(Let's replace that with a .env.development or .env.staging file.)
|
||||
|
||||
(Note: The test BVC_MEETUPS_PROJECT_CLAIM_ID does not resolve as a URL because it's only in the test DB and the prod redirect won't redirect there.)
|
||||
|
||||
* For prod, get on the server and run the correct build:
|
||||
|
||||
... and log onto the server:
|
||||
|
||||
* `pkgx +npm sh`
|
||||
|
||||
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 0.3.36 && npm install && npm run build && cd -`
|
||||
|
||||
(The plain `npm run build` uses the .env.production file.)
|
||||
|
||||
* Back up the time-safari/dist folder, then `mv time-safari/dist time-safari-dist-prev.0 && mv crowd-funder-for-time-pwa/dist time-safari/`
|
||||
|
||||
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, and commit. Also record what version is on production.
|
||||
|
||||
|
||||
|
||||
## Setup & Building
|
||||
|
||||
See [BUILDING.md](BUILDING.md) for detailed build and setup instructions.
|
||||
|
||||
## Tests
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
// Check if running in dev mode
|
||||
const isDev = process.argv.includes('--inspect');
|
||||
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));
|
||||
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({
|
||||
@@ -20,7 +20,7 @@ function createWindow() {
|
||||
contextIsolation: true,
|
||||
webSecurity: true,
|
||||
allowRunningInsecureContent: false,
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
preload: path.join(__dirname, "preload.js"),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -33,30 +33,32 @@ function createWindow() {
|
||||
console.log("__dirname:", __dirname);
|
||||
console.log("process.cwd():", process.cwd());
|
||||
|
||||
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'));
|
||||
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"));
|
||||
|
||||
if (!fs.existsSync(indexPath)) {
|
||||
console.error(`Index file not found at: ${indexPath}`);
|
||||
throw new Error('Index file not found');
|
||||
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:;"
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
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
|
||||
@@ -79,17 +81,23 @@ function createWindow() {
|
||||
});
|
||||
|
||||
// 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(
|
||||
"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('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);
|
||||
});
|
||||
mainWindow.webContents.on(
|
||||
"console-message",
|
||||
(event, level, message, line, sourceId) => {
|
||||
console.log("Renderer Console:", line, sourceId, message);
|
||||
},
|
||||
);
|
||||
|
||||
// Enable remote debugging when in dev mode
|
||||
if (isDev) {
|
||||
|
||||
@@ -1,39 +1,40 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
const { contextBridge, ipcRenderer } = require("electron");
|
||||
|
||||
// Use a more direct path resolution approach
|
||||
const getPath = (pathType) => {
|
||||
switch(pathType) {
|
||||
case 'userData':
|
||||
return process.env.APPDATA || (
|
||||
process.platform === 'darwin'
|
||||
switch (pathType) {
|
||||
case "userData":
|
||||
return (
|
||||
process.env.APPDATA ||
|
||||
(process.platform === "darwin"
|
||||
? `${process.env.HOME}/Library/Application Support`
|
||||
: `${process.env.HOME}/.local/share`
|
||||
: `${process.env.HOME}/.local/share`)
|
||||
);
|
||||
case 'home':
|
||||
case "home":
|
||||
return process.env.HOME;
|
||||
case 'appPath':
|
||||
case "appPath":
|
||||
return process.resourcesPath;
|
||||
default:
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
console.log('Preload script starting...');
|
||||
console.log("Preload script starting...");
|
||||
|
||||
try {
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
contextBridge.exposeInMainWorld("electronAPI", {
|
||||
// Path utilities
|
||||
getPath,
|
||||
|
||||
|
||||
// IPC functions
|
||||
send: (channel, data) => {
|
||||
const validChannels = ['toMain'];
|
||||
const validChannels = ["toMain"];
|
||||
if (validChannels.includes(channel)) {
|
||||
ipcRenderer.send(channel, data);
|
||||
}
|
||||
},
|
||||
receive: (channel, func) => {
|
||||
const validChannels = ['fromMain'];
|
||||
const validChannels = ["fromMain"];
|
||||
if (validChannels.includes(channel)) {
|
||||
ipcRenderer.on(channel, (event, ...args) => func(...args));
|
||||
}
|
||||
@@ -41,15 +42,15 @@ try {
|
||||
// Environment info
|
||||
env: {
|
||||
isElectron: true,
|
||||
isDev: process.env.NODE_ENV === 'development'
|
||||
isDev: process.env.NODE_ENV === "development",
|
||||
},
|
||||
// Path utilities
|
||||
getBasePath: () => {
|
||||
return process.env.NODE_ENV === 'development' ? '/' : './';
|
||||
}
|
||||
return process.env.NODE_ENV === "development" ? "/" : "./";
|
||||
},
|
||||
});
|
||||
|
||||
console.log('Preload script completed successfully');
|
||||
console.log("Preload script completed successfully");
|
||||
} catch (error) {
|
||||
console.error('Error in preload script:', error);
|
||||
}
|
||||
console.error("Error in preload script:", error);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
import { register } from "register-service-worker";
|
||||
|
||||
// Only register service worker if explicitly enabled and in production
|
||||
if (process.env.VITE_PWA_ENABLED === 'true' && process.env.NODE_ENV === "production") {
|
||||
if (
|
||||
process.env.VITE_PWA_ENABLED === "true" &&
|
||||
process.env.NODE_ENV === "production"
|
||||
) {
|
||||
register(`${process.env.BASE_URL}sw.js`, {
|
||||
ready() {
|
||||
console.log("Service worker is active.");
|
||||
@@ -21,12 +24,16 @@ if (process.env.VITE_PWA_ENABLED === 'true' && process.env.NODE_ENV === "product
|
||||
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");
|
||||
console.log(
|
||||
"Service worker registration skipped - not enabled or not in production",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
|
||||
const isElectron = window.location.protocol === "file:";
|
||||
const initialPath = isElectron
|
||||
? window.location.pathname.split('/dist-electron/www/')[1] || '/'
|
||||
? window.location.pathname.split("/dist-electron/www/")[1] || "/"
|
||||
: window.location.pathname;
|
||||
|
||||
const history = isElectron
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as path from "path";
|
||||
import { promises as fs } from "fs";
|
||||
import { fileURLToPath } from 'url';
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
export async function loadAppConfig() {
|
||||
const packageJson = await loadPackageJson();
|
||||
@@ -34,15 +34,16 @@ export async function loadAppConfig() {
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "maskable",
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
aliasConfig: {
|
||||
"@": 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",
|
||||
}
|
||||
"dexie-export-import/dist/import":
|
||||
"dexie-export-import/dist/import/index.js",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user