Skip to content

Commit a81f8c6

Browse files
committed
feat: ThemeProvider updates System themes relative to systemThemeVersion state
feat: core.css and fancy.css changes during dev are applied without a window reload refactor: Improve ThemeProvider readability refactor: Replace fs.watch with chokidar in FolderWatcher for more consistent behaviour across different operating systems fix: Wait for new theme css to load before unloading old to prevent flickering fix: Prevent file reads flagging FolderWatcher change events
1 parent dee286e commit a81f8c6

File tree

15 files changed

+424
-377
lines changed

15 files changed

+424
-377
lines changed

gulpfile.mjs

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -228,35 +228,39 @@ async function killProcess(proc) {
228228
});
229229
}
230230

231-
async function watchBackend() {
232-
await copyNativeModule();
233-
const config = await loadConfig({ path: 'rsbuild-back.config.ts'});
234-
const rsbuild = await createRsbuild({
235-
rsbuildConfig: {
236-
...config.content,
237-
},
238-
});
239-
let backProc = null;
240-
rsbuild.onAfterBuild(async () => {
241-
// Restart backend after it's been built
242-
console.log('Restarting Backend...');
243-
if (backProc) {
244-
console.log('Killing existing backend process...');
245-
await killProcess(backProc);
246-
backProc = null;
231+
function watchBackend(withServer) {
232+
return async () => {
233+
await copyNativeModule();
234+
const config = await loadConfig({ path: 'rsbuild-back.config.ts'});
235+
const rsbuild = await createRsbuild({
236+
rsbuildConfig: {
237+
...config.content,
238+
},
239+
});
240+
let backProc = null;
241+
if (withServer) {
242+
rsbuild.onAfterBuild(async () => {
243+
// Restart backend after it's been built
244+
console.log('Restarting Backend...');
245+
if (backProc) {
246+
console.log('Killing existing backend process...');
247+
await killProcess(backProc);
248+
backProc = null;
249+
}
250+
251+
backProc = spawn('node', [
252+
'--inspect=9229', // Enable debugging
253+
'build/back/backend.js'
254+
], {
255+
stdio: 'inherit',
256+
env: { ...process.env, NODE_ENV: 'development' }
257+
});
258+
});
247259
}
248-
249-
backProc = spawn('node', [
250-
'--inspect=9229', // Enable debugging
251-
'build/back/backend.js'
252-
], {
253-
stdio: 'inherit',
254-
env: { ...process.env, NODE_ENV: 'development' }
260+
await rsbuild.build({
261+
watch: true,
255262
});
256-
});
257-
await rsbuild.build({
258-
watch: true,
259-
});
263+
}
260264
}
261265

262266
async function watchRenderer() {
@@ -497,7 +501,7 @@ export const watch = series(
497501
installCrossDeps,
498502
buildStatic,
499503
parallel(
500-
watchBackend,
504+
watchBackend(false),
501505
watchElectron,
502506
watchElectronPreload,
503507
watchRenderer,
@@ -512,7 +516,7 @@ export const watchStatic = series(
512516
buildStatic,
513517
buildExtensions,
514518
parallel(
515-
watchBackend,
519+
watchBackend(true),
516520
watchStaticTask,
517521
)
518522
);

package-lock.json

Lines changed: 60 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"@types/ws": "8.18.1",
7474
"axios": "1.13.2",
7575
"babel-plugin-react-compiler": "1.0.0",
76+
"chokidar": "^4.0.3",
7677
"cross-env": "7.0.2",
7778
"dns-packet": "^5.6.1",
7879
"electron": "22.3.27",

src/back/Themes.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { BackOut } from '@shared/back/types';
22
import { parseThemeMetaData, Theme, themeEntryFilename } from '@shared/ThemeFile';
3+
import { ThemeMeta } from 'flashpoint-launcher';
34
import * as fs from 'fs-extra';
45
import * as path from 'node:path';
56
import { Registry } from './extensions/types';
67
import { SocketServer } from './SocketServer';
7-
import { ThemeState } from './types';
8+
import { BackState, ThemeState } from './types';
89
import { FolderWatcher } from './util/FolderWatcher';
9-
import { ThemeMeta } from 'flashpoint-launcher';
1010

1111
/**
1212
* Starts a watcher for a newly registered theme
@@ -57,6 +57,7 @@ export async function newThemeWatcher(id: string, basePath: string, themePath: s
5757
watcher.on('change', (filename: string, offsetPath: string) => {
5858
themeState.queue.push(() => {
5959
const relativePath = path.join(offsetPath, filename);
60+
console.log(`CHANGE (File Path: "${filename}", Theme: "${theme.themePath}")`);
6061
if (!theme.files.includes(relativePath)) {
6162
log.warn('Launcher', 'A file has been changed in a theme but the file is not registered '+
6263
`(File Path: "${filename}", Theme: "${theme.themePath}")`);
@@ -113,3 +114,45 @@ export async function newThemeWatcher(id: string, basePath: string, themePath: s
113114
registry.themes.set(theme.id, theme);
114115
watcher.watch(themePath, { recursionDepth: -1 });
115116
}
117+
118+
/**
119+
* Starts a watcher for system theme files (core.css and fancy.css) during development
120+
* Watches the build/window/styles/ folder and broadcasts changes to connected clients
121+
*
122+
* @param stylesPath Path to the styles folder (build/window/styles/)
123+
* @param socketServer Socket Server to broadcast changes on
124+
*/
125+
export async function newSystemThemeWatcher(stylesPath: string, state: BackState): Promise<void> {
126+
// Check styles path exists
127+
await fs.promises.stat(stylesPath)
128+
.catch((error) => {
129+
let errStr = '';
130+
if (error.code === 'ENOENT') {
131+
errStr += `Failed to watch styles folder. Path does not exist (Path: "${stylesPath}")\n`;
132+
}
133+
errStr += (typeof error.toString === 'function') ? error.toString() : (error + '');
134+
throw new Error(errStr);
135+
});
136+
137+
// Set up watcher (no recursion needed for flat styles folder)
138+
const watcher = new FolderWatcher();
139+
140+
watcher.on('ready', () => {
141+
// Watch for changes to CSS files
142+
watcher.on('change', (filename: string) => {
143+
if (filename.endsWith('.css')) {
144+
state.socketServer.broadcast(BackOut.SYSTEM_THEME_CHANGE);
145+
}
146+
});
147+
148+
watcher.on('add', (filename: string) => {
149+
if (filename.endsWith('.css')) {
150+
state.socketServer.broadcast(BackOut.SYSTEM_THEME_CHANGE);
151+
}
152+
});
153+
});
154+
155+
watcher.on('error', (err) => log.error('Launcher', `System theme watcher error: ${err.message}`));
156+
157+
watcher.watch(stylesPath, { recursionDepth: 0, changeDebounce: 100 });
158+
}

src/back/index.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { PreferencesFile } from '@shared/preferences/PreferencesFile';
77
import { defaultPreferencesData } from '@shared/preferences/util';
88
import { Theme } from '@shared/ThemeFile';
99
import {
10-
UnrecoverableError,
1110
createErrorProxy, deepCopy,
1211
removeFileExtension,
1312
stringifyArray
@@ -36,6 +35,7 @@ import {
3635
} from '@shared/constants';
3736
import { formatString } from '@shared/utils/StringFormatter';
3837
import { ComponentStatus, IBackProcessInfo, ILogoSet, LangFileContent, RecursivePartial } from 'flashpoint-launcher';
38+
import { UnrecoverableError } from 'flashpoint-launcher-renderer';
3939
import { parseArgs } from 'node:util';
4040
import { Tail } from 'tail';
4141
import { ConfigFile } from './ConfigFile';
@@ -68,7 +68,7 @@ import { PlaylistFile } from './PlaylistFile';
6868
import { registerRequestCallbacks } from './responses';
6969
import { ServicesFile } from './ServicesFile';
7070
import { SocketServer } from './SocketServer';
71-
import { newThemeWatcher } from './Themes';
71+
import { newSystemThemeWatcher, newThemeWatcher } from './Themes';
7272
import { BackState, ImageDownloadItem } from './types';
7373
import { awaitDialog } from './util/dialog';
7474
import { EventQueue } from './util/EventQueue';
@@ -708,6 +708,15 @@ async function prepForInit(initConfig: BackInitArgs): Promise<void> {
708708
}
709709
}
710710

711+
// Setup system theme listener for dev
712+
if (state.isDev) {
713+
try {
714+
newSystemThemeWatcher('./build/window/styles', state);
715+
} catch (error) {
716+
log.error('Laucher', 'Failed to start System theme watcher despite being in dev mode');
717+
}
718+
}
719+
711720
console.log('Back - Initialized Themes');
712721

713722
const sysEnvMiddleware = new SystemEnvMiddleware();

0 commit comments

Comments
 (0)