Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open initial electron window early and reuse it later #12897

Merged

Conversation

planger
Copy link
Contributor

@planger planger commented Sep 12, 2023

What it does

This avoids having a rather long pause from Theia start until something is visibly coming up. In my initial experiment, I observe the empty window showing up ~1.5s earlier than usual.

This behavior can be controlled via the application config in the application's package.json. For instance, to turn off, use:

  "theia": {
    "target": "electron",
    "frontend": {
      "config": {
        "applicationName": "Theia Electron Example",
        "electron": {
          "showWindowEarly": false
        }
      }
    }
  }

To mitigate flickering, we set a background color of the window, which shows before any page is loaded, according to the expected background color of the Theia app. Also, we store the background color of the current color theme to be able to show the correct background color in the initial window.

In future changes, we may consider loading a very simple static web page mimicking the basic workbench structure before we switch to the actual application and in the Theia app don't show a spinner but a loading indicator on top of the basic workbench structure. With that, the application rather builds up visually instead of flickering between nothing, the spinner and the actual app.

Contributed on behalf of STMicroelectronics.

Without this change
without.this.change.mp4
With this change
with.this.change.mp4

How to test

Build the example electron app with "showWindowEarly": false and with "showWindowEarly": true to compare the differences.

In addition, it is worth testing the following aspects:

  • Window size is correctly restored after opening the electron app
  • Window layout is correctly restored after opening the electron app
  • Opening a new window from the app works as before

Review checklist

Reminder for reviewers

@planger planger force-pushed the open-electron-window-early branch 3 times, most recently from a456a9a to 7c18dce Compare September 12, 2023 18:45
@kittaakos
Copy link
Contributor

This change aims to avoid having a rather long pause from Theia start until something is visibly coming up and thus intents to improve the perceived performance. Also it aims to prevent users from wondering whether the application is actually starting, as they don't have any feedback for several seconds when opening Theia.

This is a great start, but it would also be great to fix the problem instead of showing a fake window. Also, how will this work when multiple windows have to be restored when the app starts?

According to my profiling, a lot of time is spent with the backend starting and loading the plugin contributions and the languages, especially when there are many, and parsing the JSON files takes time.

It would be great to move the plugin loading to a worker. This is what it takes currently:

deployplugin.mp4

My initial tweak to overcome it is to avoid awaiting when reading the contributions: kittaakos/arduino-ide@b788005. The backend starts earlier, and the electron window opens earlier.

@@ -242,6 +245,16 @@ export class ElectronMainApplication {
return this.didUseNativeWindowFrameOnStart.get(webContents.id) ? 'native' : 'custom';
}

protected showInitialWindow(): void {
if (!process.env.SKIP_INITIAL_WINDOW) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can one configure this when there is a final bundled app?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the property to the electron frontend app config to make this configurable downstream.

export interface Partial {
/**
* Override or add properties to the electron `windowOptions`.
*
* Defaults to `{}`.
*/
readonly windowOptions?: BrowserWindowConstructorOptions;
}

@sdirix
Copy link
Member

sdirix commented Sep 13, 2023

This is a great start, but it would also be great to fix the problem instead of showing a fake window

In my opinion it's always better to show something instead of showing nothing. So opening a window as early as is technically possible will always be a good solution as the user gets the earliest visual feedback possible.

Obviously it would also be great to show meaningful content as fast as possible, so any performance gain there is certainly welcomed. However I don't see why we should not open the Electron window at the earliest possible point. It's not a "fake", it's just early without content.

You can also compare this to VS Code where they also open the window at the earliest point and only gradually populate it with content. It certainly helps for the perception of being fast, even if the app is actually usable only a few seconds later.

@tsmaeder
Copy link
Contributor

@kittaakos @sdirix I think we're talking about different things here: one is the perception of performance and the other is effective performance. Both contribute to user satisfaction. Things like putting up a splash screen do not make loading faster, but users still want to see something is happening. Ideally, we would show some loading progress on the "early window".

@JonasHelming
Copy link
Contributor

I agree to all said above. @kittaakos It is worth mentioning that we are currently investigating the start up performance in general, this PR is just one piece. It seems you are working in the same area. I believe it would make sense to align a bit to share ideas and avoid duplicate work. Are you interested in this? If so, maybe you join the next dev call and maybe we can schedule a break out session there for interested parties?

@kittaakos
Copy link
Contributor

Are you interested in this?

Sure. Thank you! I saved the date of the next dev call.

@planger planger mentioned this pull request Sep 19, 2023
11 tasks
@planger
Copy link
Contributor Author

planger commented Sep 19, 2023

For references, this is the epic to track all current streams of work around start-up performance improvements: #12924

@@ -242,6 +245,16 @@ export class ElectronMainApplication {
return this.didUseNativeWindowFrameOnStart.get(webContents.id) ? 'native' : 'custom';
}

protected showInitialWindow(): void {
if (!process.env.SKIP_INITIAL_WINDOW) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the property to the electron frontend app config to make this configurable downstream.

export interface Partial {
/**
* Override or add properties to the electron `windowOptions`.
*
* Defaults to `{}`.
*/
readonly windowOptions?: BrowserWindowConstructorOptions;
}

@@ -303,6 +316,7 @@ export class ElectronMainApplication {
return {
show: false,
title: this.config.applicationName,
backgroundColor: nativeTheme.shouldUseDarkColors ? '#1E1E1E' : '#FFFFFF',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A similar dispatch is already at:

const value = window.localStorage.getItem(DEFAULT_BACKGROUND_COLOR_STORAGE_KEY) || (dark ? '#1E1E1E' : '#FFFFFF');

Could you single-source them somewhere here? Thanks

export type DefaultTheme = string | Readonly<{ light: string, dark: string }>;
export namespace DefaultTheme {
export function defaultForOSTheme(theme: DefaultTheme): string {
if (typeof theme === 'string') {
return theme;
}
if (
typeof window !== 'undefined' &&
window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches
) {
return theme.dark;
}
return theme.light;
}
}

@planger
Copy link
Contributor Author

planger commented Sep 26, 2023

@kittaakos Thank you very much for the helpful review! I've incorporated the changes you suggested and also enhanced the change so that we store the user's background color in the electron store to match the theme color with the initial window's background color. Unfortunately, I had to rebase to make the changes you suggested. Sorry if that makes a re-review more cumbersome.

Copy link
Contributor

@kittaakos kittaakos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified 1d630a6, and it worked for me. Thank you!

Why is it required to set the window background?

@@ -30,6 +30,8 @@ import { WindowTitleService } from '../../browser/window/window-title-service';

import '../../../src/electron-browser/menu/electron-menu-style.css';
import { MenuDto } from '../../electron-common/electron-api';
import { ThemeService } from '../../browser/theming';
import { ThemeChangeEvent } from 'src/common/theme';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { ThemeChangeEvent } from 'src/common/theme';
import { ThemeChangeEvent } from '../../common/theme';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice catch, thank you!

@planger
Copy link
Contributor Author

planger commented Sep 26, 2023

Why is it required to set the window background?

Quite some time (500ms to 1000ms) is needed until the frontend actually starts rendering and during that time the window is just empty showing the default system background. Imho it looks faster and better to already show the empty window with the background color that matches the expected background color until the actual app is loaded. It also avoids unpleasant flickering.

@kittaakos
Copy link
Contributor

Quite some time (500ms to 1000ms) is needed until the frontend actually starts rendering and during that time the window is just empty showing the default system background. Imho it looks faster and better to already show the empty window with the background color that matches the expected background color until the actual app is loaded

I understand why it is set in the electron main. Here:

https://github.com/eclipsesource/theia/blob/bd18c66d1020897215a6b856c9435c917d880442/packages/core/src/electron-main/electron-main-application.ts#L329

But how is opening and reusing the first window requires to set the background on theme change:

https://github.com/eclipsesource/theia/blob/bd18c66d1020897215a6b856c9435c917d880442/packages/core/src/electron-browser/menu/electron-menu-contribution.ts#L131-L133

Feel free to merge it though. I only want to understand what's the catch here. Thanks

@planger
Copy link
Contributor Author

planger commented Sep 26, 2023

But how is opening and reusing the first window requires to set the background on theme change:

https://github.com/eclipsesource/theia/blob/bd18c66d1020897215a6b856c9435c917d880442/packages/core/src/electron-browser/menu/electron-menu-contribution.ts#L131-L133

This is to match the background color if the user switched to a different theme. Whenever the user switches theme, we notify the Electron window and it stores the background color into the electron store, so it can be restored on next start correctly.
You can test this by switching color theme to something with a completely different background color and observe how the correct background color is shown even though the page hasn't been loaded yet on next restart.

Or am I misunderstanding the question?

@kittaakos
Copy link
Contributor

Or am I misunderstanding the question?

No, you're right. Thanks for the explanation

@planger
Copy link
Contributor Author

planger commented Sep 27, 2023

@kittaakos Great, thanks! Can you please re-approve the rebase, if you agree to merge? Thank you!

This avoids having a rather long pause from Theia start until something
is visibly coming up. In my initial experiment, I observe the empty
window showing up ~1.5s earlier than usual.

This behavior can be controlled via the application config in the
application's package.json. For instance, to turn off, use:

```
  "theia": {
    "target": "electron",
    "frontend": {
      "config": {
        "applicationName": "Theia Electron Example",
        "electron": {
          "showWindowEarly": false
        }
      }
    }
  }
```

Also, we store the background color of the current color theme
to be able to show the correct background color in the initial
window.

Contributed on behalf of STMicroelectronics.

Change-Id: Ib8a6e8221c4f48605c865afc120d62adf6eef902
@planger planger removed the request for review from tsmaeder September 28, 2023 12:08
@planger planger merged commit 45a0953 into eclipse-theia:master Sep 28, 2023
12 checks passed
@planger planger deleted the open-electron-window-early branch September 28, 2023 12:48
@vince-fugnitto vince-fugnitto added the electron issues related to the electron target label Sep 28, 2023
@vince-fugnitto vince-fugnitto added this to the 1.42.0 milestone Sep 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
electron issues related to the electron target
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

6 participants