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.
|
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.)
|
(Numbers at the beginning of lines are estimated hours. See [taskyaml.org](https://taskyaml.org/) for details.)
|
||||||
|
|
||||||
## Setup
|
## Setup & Building
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
See [BUILDING.md](BUILDING.md) for detailed build and setup instructions.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ const path = require("path");
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
// Check if running in dev mode
|
// Check if running in dev mode
|
||||||
const isDev = process.argv.includes('--inspect');
|
const isDev = process.argv.includes("--inspect");
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
// Add before createWindow function
|
// Add before createWindow function
|
||||||
const preloadPath = path.join(__dirname, 'preload.js');
|
const preloadPath = path.join(__dirname, "preload.js");
|
||||||
console.log('Checking preload path:', preloadPath);
|
console.log("Checking preload path:", preloadPath);
|
||||||
console.log('Preload exists:', fs.existsSync(preloadPath));
|
console.log("Preload exists:", fs.existsSync(preloadPath));
|
||||||
|
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
const mainWindow = new BrowserWindow({
|
const mainWindow = new BrowserWindow({
|
||||||
@@ -20,7 +20,7 @@ function createWindow() {
|
|||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
webSecurity: true,
|
webSecurity: true,
|
||||||
allowRunningInsecureContent: false,
|
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("__dirname:", __dirname);
|
||||||
console.log("process.cwd():", process.cwd());
|
console.log("process.cwd():", process.cwd());
|
||||||
|
|
||||||
const indexPath = path.join(__dirname, 'www', 'index.html');
|
const indexPath = path.join(__dirname, "www", "index.html");
|
||||||
console.log("www path:", path.join(__dirname, 'www'));
|
console.log("www path:", path.join(__dirname, "www"));
|
||||||
console.log("www assets path:", path.join(__dirname, 'www', 'assets'));
|
console.log("www assets path:", path.join(__dirname, "www", "assets"));
|
||||||
|
|
||||||
if (!fs.existsSync(indexPath)) {
|
if (!fs.existsSync(indexPath)) {
|
||||||
console.error(`Index file not found at: ${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
|
// Set CSP headers
|
||||||
mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
|
mainWindow.webContents.session.webRequest.onHeadersReceived(
|
||||||
callback({
|
(details, callback) => {
|
||||||
responseHeaders: {
|
callback({
|
||||||
...details.responseHeaders,
|
responseHeaders: {
|
||||||
'Content-Security-Policy': [
|
...details.responseHeaders,
|
||||||
"default-src 'self';" +
|
"Content-Security-Policy": [
|
||||||
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;" +
|
"default-src 'self';" +
|
||||||
"font-src 'self' https://fonts.gstatic.com;" +
|
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;" +
|
||||||
"script-src 'self' 'unsafe-eval' 'unsafe-inline';" +
|
"font-src 'self' https://fonts.gstatic.com;" +
|
||||||
"img-src 'self' data: https:;"
|
"script-src 'self' 'unsafe-eval' 'unsafe-inline';" +
|
||||||
]
|
"img-src 'self' data: https:;",
|
||||||
}
|
],
|
||||||
});
|
},
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Load the index.html
|
// Load the index.html
|
||||||
mainWindow
|
mainWindow
|
||||||
@@ -79,17 +81,23 @@ function createWindow() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add right after creating the BrowserWindow
|
// Add right after creating the BrowserWindow
|
||||||
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
|
mainWindow.webContents.on(
|
||||||
console.error('Page failed to load:', errorCode, errorDescription);
|
"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) => {
|
mainWindow.webContents.on(
|
||||||
console.error('Preload script error:', preloadPath, error);
|
"console-message",
|
||||||
});
|
(event, level, message, line, sourceId) => {
|
||||||
|
console.log("Renderer Console:", line, sourceId, message);
|
||||||
mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => {
|
},
|
||||||
console.log('Renderer Console:', message);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
// Enable remote debugging when in dev mode
|
// Enable remote debugging when in dev mode
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
|
|||||||
@@ -1,39 +1,40 @@
|
|||||||
const { contextBridge, ipcRenderer } = require('electron');
|
const { contextBridge, ipcRenderer } = require("electron");
|
||||||
|
|
||||||
// Use a more direct path resolution approach
|
// Use a more direct path resolution approach
|
||||||
const getPath = (pathType) => {
|
const getPath = (pathType) => {
|
||||||
switch(pathType) {
|
switch (pathType) {
|
||||||
case 'userData':
|
case "userData":
|
||||||
return process.env.APPDATA || (
|
return (
|
||||||
process.platform === 'darwin'
|
process.env.APPDATA ||
|
||||||
|
(process.platform === "darwin"
|
||||||
? `${process.env.HOME}/Library/Application Support`
|
? `${process.env.HOME}/Library/Application Support`
|
||||||
: `${process.env.HOME}/.local/share`
|
: `${process.env.HOME}/.local/share`)
|
||||||
);
|
);
|
||||||
case 'home':
|
case "home":
|
||||||
return process.env.HOME;
|
return process.env.HOME;
|
||||||
case 'appPath':
|
case "appPath":
|
||||||
return process.resourcesPath;
|
return process.resourcesPath;
|
||||||
default:
|
default:
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Preload script starting...');
|
console.log("Preload script starting...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
contextBridge.exposeInMainWorld("electronAPI", {
|
||||||
// Path utilities
|
// Path utilities
|
||||||
getPath,
|
getPath,
|
||||||
|
|
||||||
// IPC functions
|
// IPC functions
|
||||||
send: (channel, data) => {
|
send: (channel, data) => {
|
||||||
const validChannels = ['toMain'];
|
const validChannels = ["toMain"];
|
||||||
if (validChannels.includes(channel)) {
|
if (validChannels.includes(channel)) {
|
||||||
ipcRenderer.send(channel, data);
|
ipcRenderer.send(channel, data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
receive: (channel, func) => {
|
receive: (channel, func) => {
|
||||||
const validChannels = ['fromMain'];
|
const validChannels = ["fromMain"];
|
||||||
if (validChannels.includes(channel)) {
|
if (validChannels.includes(channel)) {
|
||||||
ipcRenderer.on(channel, (event, ...args) => func(...args));
|
ipcRenderer.on(channel, (event, ...args) => func(...args));
|
||||||
}
|
}
|
||||||
@@ -41,15 +42,15 @@ try {
|
|||||||
// Environment info
|
// Environment info
|
||||||
env: {
|
env: {
|
||||||
isElectron: true,
|
isElectron: true,
|
||||||
isDev: process.env.NODE_ENV === 'development'
|
isDev: process.env.NODE_ENV === "development",
|
||||||
},
|
},
|
||||||
// Path utilities
|
// Path utilities
|
||||||
getBasePath: () => {
|
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) {
|
} 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";
|
import { register } from "register-service-worker";
|
||||||
|
|
||||||
// Only register service worker if explicitly enabled and in production
|
// 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`, {
|
register(`${process.env.BASE_URL}sw.js`, {
|
||||||
ready() {
|
ready() {
|
||||||
console.log("Service worker is active.");
|
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.");
|
console.log("New content is available; please refresh.");
|
||||||
},
|
},
|
||||||
offline() {
|
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) {
|
error(error) {
|
||||||
console.error("Error during service worker registration:", error);
|
console.error("Error during service worker registration:", error);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} 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 isElectron = window.location.protocol === "file:";
|
||||||
const initialPath = isElectron
|
const initialPath = isElectron
|
||||||
? window.location.pathname.split('/dist-electron/www/')[1] || '/'
|
? window.location.pathname.split("/dist-electron/www/")[1] || "/"
|
||||||
: window.location.pathname;
|
: window.location.pathname;
|
||||||
|
|
||||||
const history = isElectron
|
const history = isElectron
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
export async function loadAppConfig() {
|
export async function loadAppConfig() {
|
||||||
const packageJson = await loadPackageJson();
|
const packageJson = await loadPackageJson();
|
||||||
@@ -34,15 +34,16 @@ export async function loadAppConfig() {
|
|||||||
sizes: "512x512",
|
sizes: "512x512",
|
||||||
type: "image/png",
|
type: "image/png",
|
||||||
purpose: "maskable",
|
purpose: "maskable",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
aliasConfig: {
|
aliasConfig: {
|
||||||
"@": path.resolve(path.dirname(__dirname), "src"),
|
"@": path.resolve(path.dirname(__dirname), "src"),
|
||||||
buffer: path.resolve(path.dirname(__dirname), "node_modules", "buffer"),
|
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