mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(electron): restore packaged desktop app loading (#1095)
* fix(electron): restore packaged desktop app loading Rebuild and verify Electron native modules before packaging and use the Vite base URL for packaged asset preloads. * test(preload-utils): cover non-root base urls
This commit is contained in:
@@ -252,6 +252,9 @@ jobs:
|
|||||||
ls -la build/electron/preload.cjs || exit 1
|
ls -la build/electron/preload.cjs || exit 1
|
||||||
ls -la build/index.html || exit 1
|
ls -la build/index.html || exit 1
|
||||||
|
|
||||||
|
- name: Rebuild and verify Electron native modules
|
||||||
|
run: yarn electron:prepare-package
|
||||||
|
|
||||||
- name: Package Electron app
|
- name: Package Electron app
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
run: |
|
run: |
|
||||||
@@ -314,6 +317,9 @@ jobs:
|
|||||||
ls -la build/electron/preload.cjs || exit 1
|
ls -la build/electron/preload.cjs || exit 1
|
||||||
ls -la build/index.html || exit 1
|
ls -la build/index.html || exit 1
|
||||||
|
|
||||||
|
- name: Rebuild and verify Electron native modules
|
||||||
|
run: yarn electron:prepare-package
|
||||||
|
|
||||||
- name: Package Electron app
|
- name: Package Electron app
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
run: |
|
run: |
|
||||||
@@ -376,6 +382,9 @@ jobs:
|
|||||||
ls -la build/electron/preload.cjs || exit 1
|
ls -la build/electron/preload.cjs || exit 1
|
||||||
ls -la build/index.html || exit 1
|
ls -la build/index.html || exit 1
|
||||||
|
|
||||||
|
- name: Rebuild and verify Electron native modules
|
||||||
|
run: yarn electron:prepare-package
|
||||||
|
|
||||||
- name: Package Electron app
|
- name: Package Electron app
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
run: |
|
run: |
|
||||||
@@ -439,6 +448,10 @@ jobs:
|
|||||||
ls -la build/electron/preload.cjs || exit 1
|
ls -la build/electron/preload.cjs || exit 1
|
||||||
ls -la build/index.html || exit 1
|
ls -la build/index.html || exit 1
|
||||||
|
|
||||||
|
- name: Rebuild and verify Electron native modules
|
||||||
|
shell: bash
|
||||||
|
run: yarn electron:prepare-package
|
||||||
|
|
||||||
- name: Package Electron app
|
- name: Package Electron app
|
||||||
shell: bash
|
shell: bash
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
|
|||||||
@@ -47,3 +47,13 @@ If uncertain, ask the developer before adding an entry.
|
|||||||
- **Impact:** Agents may “fix” the unlisted import by adding `@plebbit/plebbit-js` to `package.json`, which violates project policy.
|
- **Impact:** Agents may “fix” the unlisted import by adding `@plebbit/plebbit-js` to `package.json`, which violates project policy.
|
||||||
- **Mitigation:** Do not add `@plebbit/plebbit-js` to `package.json` for this repo. If `knip` flags `electron/start-plebbit-rpc.js`, handle it with a targeted `ignoreIssues` entry instead.
|
- **Mitigation:** Do not add `@plebbit/plebbit-js` to `package.json` for this repo. If `knip` flags `electron/start-plebbit-rpc.js`, handle it with a targeted `ignoreIssues` entry instead.
|
||||||
- **Status:** confirmed
|
- **Status:** confirmed
|
||||||
|
|
||||||
|
### Electron packaging can ship a broken `better-sqlite3` binary
|
||||||
|
|
||||||
|
- **Date:** 2026-03-17
|
||||||
|
- **Observed by:** Codex
|
||||||
|
- **Context:** Investigating the `v0.7.1` macOS arm64 DMG after the app showed a live IPFS node but never loaded boards or comments.
|
||||||
|
- **What was surprising:** The packaged app can start IPFS successfully while `electron/start-plebbit-rpc.js` loops forever because `/Applications/5chan.app/.../better_sqlite3.node` was built for plain Node 22 (`NODE_MODULE_VERSION 127`) instead of Electron 36 (`NODE_MODULE_VERSION 135`).
|
||||||
|
- **Impact:** The local RPC server on `ws://localhost:9138` never starts, so the desktop app cannot load boards, posts, or comments even though node stats look healthy.
|
||||||
|
- **Mitigation:** Before any Electron package/build job, run `yarn electron:prepare-package` so `better-sqlite3` is rebuilt for Electron and immediately verified via `ELECTRON_RUN_AS_NODE=1 electron`.
|
||||||
|
- **Status:** confirmed
|
||||||
|
|||||||
+12
-9
@@ -62,15 +62,18 @@
|
|||||||
"electron:no-delete-data": "yarn build:preload && electron .",
|
"electron:no-delete-data": "yarn build:preload && electron .",
|
||||||
"electron:start": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://5chan.localhost:1355 && yarn electron\"",
|
"electron:start": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://5chan.localhost:1355 && yarn electron\"",
|
||||||
"electron:start:no-delete-data": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://5chan.localhost:1355 && yarn electron:no-delete-data\"",
|
"electron:start:no-delete-data": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://5chan.localhost:1355 && yarn electron:no-delete-data\"",
|
||||||
"electron:package": "yarn build && yarn build:preload && electron-forge package",
|
"electron:rebuild-native": "electron-rebuild -f -w better-sqlite3",
|
||||||
"electron:build": "yarn build && yarn build:preload && electron-forge make",
|
"electron:verify-native": "node scripts/verify-electron-native-modules.js",
|
||||||
"electron:build:linux": "yarn build && yarn build:preload && electron-forge make --platform=linux",
|
"electron:prepare-package": "yarn electron:rebuild-native && yarn electron:verify-native",
|
||||||
"electron:build:mac": "yarn build && yarn build:preload && electron-forge make --platform=darwin",
|
"electron:package": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge package",
|
||||||
"electron:build:windows": "yarn build && yarn build:preload && electron-forge make --platform=win32",
|
"electron:build": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make",
|
||||||
"electron:build:linux:x64": "yarn build && yarn build:preload && electron-forge make --platform=linux --arch=x64",
|
"electron:build:linux": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make --platform=linux",
|
||||||
"electron:build:linux:arm64": "yarn build && yarn build:preload && electron-forge make --platform=linux --arch=arm64",
|
"electron:build:mac": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make --platform=darwin",
|
||||||
"electron:build:mac:x64": "yarn build && yarn build:preload && electron-forge make --platform=darwin --arch=x64",
|
"electron:build:windows": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make --platform=win32",
|
||||||
"electron:build:mac:arm64": "yarn build && yarn build:preload && electron-forge make --platform=darwin --arch=arm64",
|
"electron:build:linux:x64": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make --platform=linux --arch=x64",
|
||||||
|
"electron:build:linux:arm64": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make --platform=linux --arch=arm64",
|
||||||
|
"electron:build:mac:x64": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make --platform=darwin --arch=x64",
|
||||||
|
"electron:build:mac:arm64": "yarn build && yarn build:preload && yarn electron:prepare-package && electron-forge make --platform=darwin --arch=arm64",
|
||||||
"electron:before": "yarn electron:before:delete-data",
|
"electron:before": "yarn electron:before:delete-data",
|
||||||
"electron:before:delete-data": "node -e \"fs.rmSync('.plebbit', { recursive: true, force: true })\"",
|
"electron:before:delete-data": "node -e \"fs.rmSync('.plebbit', { recursive: true, force: true })\"",
|
||||||
"android:build:icons": "cordova-res android --skip-config --copy --resources /tmp/plebbit-react-android-icons --icon-source ./android/icons/icon.png --splash-source ./android/icons/splash.png --icon-foreground-source ./android/icons/icon-foreground.png --icon-background-source '#ffffee'",
|
"android:build:icons": "cordova-res android --skip-config --copy --resources /tmp/plebbit-react-android-icons --icon-source ./android/icons/icon.png --splash-source ./android/icons/splash.png --icon-foreground-source ./android/icons/icon-foreground.png --icon-background-source '#ffffee'",
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const electronBinary = require('electron');
|
||||||
|
|
||||||
|
if (typeof electronBinary !== 'string' || electronBinary.length === 0) {
|
||||||
|
throw new Error('Failed to resolve the Electron executable for native-module verification');
|
||||||
|
}
|
||||||
|
|
||||||
|
const nativeModules = ['better-sqlite3'];
|
||||||
|
const verificationScript = `
|
||||||
|
console.log('electron modules', process.versions.modules);
|
||||||
|
for (const moduleName of ${JSON.stringify(nativeModules)}) {
|
||||||
|
try {
|
||||||
|
require(moduleName);
|
||||||
|
console.log('native-ok', moduleName);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('native-fail', moduleName);
|
||||||
|
console.error(error && error.stack ? error.stack : String(error));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = spawnSync(electronBinary, ['-e', verificationScript], {
|
||||||
|
encoding: 'utf8',
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
ELECTRON_RUN_AS_NODE: '1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.stdout) {
|
||||||
|
process.stdout.write(result.stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.stderr) {
|
||||||
|
process.stderr.write(result.stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.status !== 0) {
|
||||||
|
throw new Error(`Electron native-module verification failed with exit code ${result.status ?? 'unknown'}`);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { copyToClipboard } from '../clipboard-utils';
|
import { copyToClipboard } from '../clipboard-utils';
|
||||||
import { hashStringToColor, getTextColorForBackground, removeMarkdown } from '../post-utils';
|
import { hashStringToColor, getTextColorForBackground, removeMarkdown } from '../post-utils';
|
||||||
import { preloadReplyModal, preloadThemeAssets } from '../preload-utils';
|
import { preloadReplyModal, preloadThemeAssets, resolveAssetUrl } from '../preload-utils';
|
||||||
import { computeOmittedCount, filterRepliesForDisplay, getPreviewDisplayReplies, getTotalReplyCount } from '../replies-preview-utils';
|
import { computeOmittedCount, filterRepliesForDisplay, getPreviewDisplayReplies, getTotalReplyCount } from '../replies-preview-utils';
|
||||||
import { getQuotedCidsFromContent, mergeQuotedCids } from '../reply-quote-utils';
|
import { getQuotedCidsFromContent, mergeQuotedCids } from '../reply-quote-utils';
|
||||||
import { formatUserIDForDisplay, truncateWithEllipsisInMiddle } from '../string-utils';
|
import { formatUserIDForDisplay, truncateWithEllipsisInMiddle } from '../string-utils';
|
||||||
@@ -116,7 +116,16 @@ describe('misc utils', () => {
|
|||||||
|
|
||||||
preloadThemeAssets();
|
preloadThemeAssets();
|
||||||
|
|
||||||
expect(loadedSources).toEqual(['/buttons/default.png', '/buttons/hover.png', '/backgrounds/wallpaper.png']);
|
expect(loadedSources).toEqual([
|
||||||
|
`${import.meta.env.BASE_URL}buttons/default.png`,
|
||||||
|
`${import.meta.env.BASE_URL}buttons/hover.png`,
|
||||||
|
`${import.meta.env.BASE_URL}backgrounds/wallpaper.png`,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves theme asset URLs against a non-root base URL', () => {
|
||||||
|
expect(resolveAssetUrl('buttons/default.png', 'file:///app/')).toBe('file:///app/buttons/default.png');
|
||||||
|
expect(resolveAssetUrl('backgrounds/wallpaper.png', 'file:///app/')).toBe('file:///app/backgrounds/wallpaper.png');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('schedules reply modal preload with requestIdleCallback when available', () => {
|
it('schedules reply modal preload with requestIdleCallback when available', () => {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { THEME_BUTTON_IMAGES, THEME_BACKGROUND_IMAGES } from '../../generated/asset-manifest';
|
import { THEME_BUTTON_IMAGES, THEME_BACKGROUND_IMAGES } from '../../generated/asset-manifest';
|
||||||
|
|
||||||
|
export const resolveAssetUrl = (path: string, baseUrl = import.meta.env.BASE_URL): string => `${baseUrl}${path}`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preloads an array of image URLs by creating Image objects.
|
* Preloads an array of image URLs by creating Image objects.
|
||||||
* Images are loaded in the background and cached by the browser.
|
* Images are loaded in the background and cached by the browser.
|
||||||
@@ -7,7 +9,7 @@ import { THEME_BUTTON_IMAGES, THEME_BACKGROUND_IMAGES } from '../../generated/as
|
|||||||
const preloadImages = (imagePaths: readonly string[]): void => {
|
const preloadImages = (imagePaths: readonly string[]): void => {
|
||||||
imagePaths.forEach((path) => {
|
imagePaths.forEach((path) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.src = `/${path}`;
|
img.src = resolveAssetUrl(path);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user