Skip to content

Commit 636333b

Browse files
authored
Merge pull request #4006 from illume/app-load
app: Load time performance improvements up to 1.6x faster
2 parents 305c146 + f01b6cd commit 636333b

File tree

9 files changed

+1178
-56
lines changed

9 files changed

+1178
-56
lines changed

app/electron/main.ts

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,6 @@ const defaultPort = 4466;
128128

129129
const useExternalServer = process.env.EXTERNAL_SERVER || false;
130130
const shouldCheckForUpdates = process.env.HEADLAMP_CHECK_FOR_UPDATES !== 'false';
131-
const manifestDir = isDev ? path.resolve('./') : process.resourcesPath;
132-
const manifestFile = path.join(manifestDir, 'app-build-manifest.json');
133-
const buildManifest = fs.existsSync(manifestFile) ? require(manifestFile) : {};
134131

135132
// make it global so that it doesn't get garbage collected
136133
let mainWindow: BrowserWindow | null;
@@ -585,6 +582,18 @@ async function startServer(flags: string[] = []): Promise<ChildProcessWithoutNul
585582
if (!!args.kubeconfig) {
586583
serverArgs = serverArgs.concat(['--kubeconfig', args.kubeconfig]);
587584
}
585+
586+
const manifestDir = isDev ? path.resolve('./') : process.resourcesPath;
587+
const manifestFile = path.join(manifestDir, 'app-build-manifest.json');
588+
let buildManifest: Record<string, any> = {};
589+
try {
590+
const manifestContent = await fsPromises.readFile(manifestFile, 'utf8');
591+
buildManifest = JSON.parse(manifestContent);
592+
} catch (err) {
593+
// If the manifest doesn't exist or can't be read, fall back to empty object
594+
buildManifest = {};
595+
}
596+
588597
const proxyUrls = !!buildManifest && buildManifest['proxy-urls'];
589598
if (!!proxyUrls && proxyUrls.length > 0) {
590599
serverArgs = serverArgs.concat(['--proxy-urls', proxyUrls.join(',')]);
@@ -603,8 +612,16 @@ async function startServer(flags: string[] = []): Promise<ChildProcessWithoutNul
603612
process.env.HEADLAMP_BACKEND_TOKEN = backendToken;
604613

605614
// Set the bundled plugins in addition to the the user's plugins.
606-
if (fs.existsSync(bundledPlugins) && fs.readdirSync(bundledPlugins).length !== 0) {
607-
process.env.HEADLAMP_STATIC_PLUGINS_DIR = bundledPlugins;
615+
try {
616+
const stat = await fsPromises.stat(bundledPlugins);
617+
if (stat.isDirectory()) {
618+
const entries = await fsPromises.readdir(bundledPlugins);
619+
if (entries.length !== 0) {
620+
process.env.HEADLAMP_STATIC_PLUGINS_DIR = bundledPlugins;
621+
}
622+
}
623+
} catch (err) {
624+
// Directory doesn't exist or is not readable — ignore and continue.
608625
}
609626

610627
serverArgs = serverArgs.concat(flags);
@@ -633,13 +650,18 @@ async function startServer(flags: string[] = []): Promise<ChildProcessWithoutNul
633650
* Are we running inside WSL?
634651
* @returns true if we are running inside WSL.
635652
*/
636-
function isWSL(): boolean {
653+
async function isWSL(): Promise<boolean> {
654+
// Cheap platform check first to avoid reading /proc on non-Linux platforms.
655+
if (platform() !== 'linux') {
656+
return false;
657+
}
658+
637659
try {
638-
const data = fs.readFileSync('/proc/version', {
660+
const data = await fsPromises.readFile('/proc/version', {
639661
encoding: 'utf8',
640-
flag: 'r',
641662
});
642-
return data.indexOf('icrosoft') !== -1;
663+
const lower = data.toLowerCase();
664+
return lower.includes('microsoft') || lower.includes('wsl');
643665
} catch {
644666
return false;
645667
}
@@ -1081,10 +1103,11 @@ function saveZoomFactor(factor: number) {
10811103
}
10821104
}
10831105

1084-
function loadZoomFactor() {
1106+
async function loadZoomFactor(): Promise<number> {
10851107
try {
1086-
const { zoomFactor = 1.0 } = JSON.parse(fs.readFileSync(ZOOM_FILE_PATH, 'utf-8'));
1087-
return zoomFactor;
1108+
const content = await fsPromises.readFile(ZOOM_FILE_PATH, 'utf-8');
1109+
const { zoomFactor = 1.0 } = JSON.parse(content);
1110+
return typeof zoomFactor === 'number' ? zoomFactor : 1.0;
10881111
} catch (err) {
10891112
console.error('Failed to load zoom factor, defaulting to 1.0:', err);
10901113
return 1.0;
@@ -1119,7 +1142,7 @@ function startElecron() {
11191142

11201143
console.log('Check for updates: ', shouldCheckForUpdates);
11211144

1122-
async function createWindow() {
1145+
async function startServerIfNeeded() {
11231146
if (!useExternalServer) {
11241147
serverProcess = await startServer();
11251148
attachServerEventHandlers(serverProcess);
@@ -1207,9 +1230,11 @@ function startElecron() {
12071230
}
12081231
});
12091232
}
1233+
}
12101234

1235+
async function createWindow() {
12111236
// WSL has a problem with full size window placement, so make it smaller.
1212-
const withMargin = isWSL();
1237+
const withMargin = await isWSL();
12131238
const { width, height } = windowSize(screen.getPrimaryDisplay().workAreaSize, withMargin);
12141239

12151240
mainWindow = new BrowserWindow({
@@ -1250,9 +1275,11 @@ function startElecron() {
12501275
}
12511276
});
12521277

1253-
mainWindow.webContents.on('did-finish-load', () => {
1254-
const startZoom = loadZoomFactor();
1255-
setZoom(startZoom);
1278+
mainWindow.webContents.on('did-finish-load', async () => {
1279+
const startZoom = await loadZoomFactor();
1280+
if (startZoom !== 1.0) {
1281+
setZoom(startZoom);
1282+
}
12561283
});
12571284

12581285
mainWindow.webContents.on('dom-ready', () => {
@@ -1419,10 +1446,12 @@ function startElecron() {
14191446
app.disableHardwareAcceleration();
14201447
}
14211448

1422-
app.on('ready', createWindow);
1423-
app.on('activate', function () {
1449+
app.on('ready', async () => {
1450+
await Promise.all([startServerIfNeeded(), createWindow()]);
1451+
});
1452+
app.on('activate', async function () {
14241453
if (mainWindow === null) {
1425-
createWindow();
1454+
await Promise.all([startServerIfNeeded(), createWindow()]);
14261455
}
14271456
});
14281457

frontend/src/components/App/Home/ClusterTable.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { ApiError } from '../../../lib/k8s/api/v2/ApiError';
2828
import { Cluster } from '../../../lib/k8s/cluster';
2929
import { getClusterPrefixedPath } from '../../../lib/util';
3030
import { useTypedSelector } from '../../../redux/hooks';
31+
import { Loader } from '../../common';
3132
import Link from '../../common/Link';
3233
import Table from '../../common/Table';
3334
import ClusterContextMenu from './ClusterContextMenu';
@@ -139,6 +140,11 @@ export default function ClusterTable({
139140
}
140141
const viewClusters = t('View Clusters');
141142

143+
const loading = clusters === null;
144+
if (loading) {
145+
return <Loader title={t('Loading...')} />;
146+
}
147+
142148
return (
143149
<Table
144150
columns={[

0 commit comments

Comments
 (0)