diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a3129b2bc79d..a4ec6233eff31 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,8 @@
[1.22.0 Milestone](https://github.com/eclipse-theia/theia/milestone/30)
+- [plugin-ext] add --fastStartup flag to wait for frontend start to deploy the plugins. [#](https://github.com/eclipse-theia/theia/pull/) - Contributed on behalf of STMicroelectronics
+
[Breaking Changes:](#breaking_changes_1.22.0)
- [core] Removed `MarkdownRenderer` class [#10589](https://github.com/eclipse-theia/theia/pull/10589)
- [core] `ContextKeyService` is now an interface. Extenders should extend `ContextKeyServiceDummyImpl` [#10546](https://github.com/eclipse-theia/theia/pull/10546)
diff --git a/packages/core/src/browser/frontend-application-module.ts b/packages/core/src/browser/frontend-application-module.ts
index fb2a485fb0d56..b42dcbd7a62af 100644
--- a/packages/core/src/browser/frontend-application-module.ts
+++ b/packages/core/src/browser/frontend-application-module.ts
@@ -30,7 +30,8 @@ import {
MessageClient,
InMemoryResources,
messageServicePath,
- InMemoryTextResourceResolver
+ InMemoryTextResourceResolver,
+ ClientConnectionNotifier
} from '../common';
import { KeybindingRegistry, KeybindingContext, KeybindingContribution } from './keybinding';
import { FrontendApplication, FrontendApplicationContribution, DefaultFrontendApplicationContribution } from './frontend-application';
@@ -390,4 +391,8 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo
child.bind(Coordinate).toConstantValue(position);
return child.get(BreadcrumbPopupContainer);
});
+ bind(ClientConnectionNotifier).toDynamicValue(ctx => {
+ const connection = ctx.container.get(WebSocketConnectionProvider);
+ return connection.createProxy('clientConnected');
+ }).inSingletonScope();
});
diff --git a/packages/core/src/browser/frontend-application.ts b/packages/core/src/browser/frontend-application.ts
index 9d2e4ad62f6cc..d0c0fee855d39 100644
--- a/packages/core/src/browser/frontend-application.ts
+++ b/packages/core/src/browser/frontend-application.ts
@@ -15,7 +15,7 @@
********************************************************************************/
import { inject, injectable, named } from 'inversify';
-import { ContributionProvider, CommandRegistry, MenuModelRegistry, isOSX } from '../common';
+import { ContributionProvider, CommandRegistry, MenuModelRegistry, isOSX, ClientConnectionNotifier } from '../common';
import { MaybePromise } from '../common/types';
import { KeybindingRegistry } from './keybinding';
import { Widget } from './widgets';
@@ -129,7 +129,8 @@ export class FrontendApplication {
@inject(ContributionProvider) @named(FrontendApplicationContribution)
protected readonly contributions: ContributionProvider,
@inject(ApplicationShell) protected readonly _shell: ApplicationShell,
- @inject(FrontendApplicationStateService) protected readonly stateService: FrontendApplicationStateService
+ @inject(FrontendApplicationStateService) protected readonly stateService: FrontendApplicationStateService,
+ @inject(ClientConnectionNotifier) protected readonly connectionNotifier: ClientConnectionNotifier
) { }
get shell(): ApplicationShell {
@@ -258,9 +259,10 @@ export class FrontendApplication {
const startupElem = this.getStartupIndicator(host);
if (startupElem) {
return new Promise(resolve => {
- window.requestAnimationFrame(() => {
+ window.requestAnimationFrame(async () => {
startupElem.classList.add('theia-hidden');
console.log(`Finished loading frontend application after ${(performance.now() / 1000).toFixed(3)} seconds`);
+ await this.connectionNotifier.clientConnected();
const preloadStyle = window.getComputedStyle(startupElem);
const transitionDuration = parseCssTime(preloadStyle.transitionDuration, 0);
window.setTimeout(() => {
diff --git a/packages/core/src/common/connection-notifier.ts b/packages/core/src/common/connection-notifier.ts
new file mode 100644
index 0000000000000..ce6af4e8eb701
--- /dev/null
+++ b/packages/core/src/common/connection-notifier.ts
@@ -0,0 +1,37 @@
+/********************************************************************************
+ * Copyright (C) 2022 STMicroelectronics and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
+ * with the GNU Classpath Exception which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ ********************************************************************************/
+import { injectable } from 'inversify';
+import * as events from 'events';
+
+export const ConnectionTimeout = Symbol('ConnectionTimeout');
+
+@injectable()
+export class ClientConnectionNotifier {
+
+ static readonly CLIENT_CONNECTED = 'clientConnected';
+
+ readonly connectionEvent = new events.EventEmitter();
+
+ currentlyConnected = false;
+
+ async clientConnected(): Promise {
+ if (!this.currentlyConnected) {
+ this.currentlyConnected = true;
+ this.connectionEvent.emit(ClientConnectionNotifier.CLIENT_CONNECTED);
+ }
+ }
+
+}
diff --git a/packages/core/src/common/index.ts b/packages/core/src/common/index.ts
index 3d041d03e68d9..2341edd7ca775 100644
--- a/packages/core/src/common/index.ts
+++ b/packages/core/src/common/index.ts
@@ -40,6 +40,7 @@ export * from './lsp-types';
export * from './contribution-filter';
export * from './nls';
export * from './numbers';
+export * from './connection-notifier';
import { environment } from '@theia/application-package/lib/environment';
export { environment };
diff --git a/packages/core/src/node/backend-application-module.ts b/packages/core/src/node/backend-application-module.ts
index 555d6974d4c25..f12188490ccbb 100644
--- a/packages/core/src/node/backend-application-module.ts
+++ b/packages/core/src/node/backend-application-module.ts
@@ -18,7 +18,7 @@ import { ContainerModule, decorate, injectable } from 'inversify';
import { ApplicationPackage } from '@theia/application-package';
import {
bindContributionProvider, MessageService, MessageClient, ConnectionHandler, JsonRpcConnectionHandler,
- CommandService, commandServicePath, messageServicePath
+ CommandService, commandServicePath, messageServicePath, ClientConnectionNotifier
} from '../common';
import { BackendApplication, BackendApplicationContribution, BackendApplicationCliContribution, BackendApplicationServer } from './backend-application';
import { CliManager, CliContribution } from './cli';
@@ -109,4 +109,8 @@ export const backendApplicationModule = new ContainerModule(bind => {
bind(EnvironmentUtils).toSelf().inSingletonScope();
bind(ProcessUtils).toSelf().inSingletonScope();
+ bind(ConnectionHandler).toDynamicValue(({container}) =>
+ new JsonRpcConnectionHandler('clientConnected', () => container.get(ClientConnectionNotifier))
+ ).inSingletonScope();
+ bind(ClientConnectionNotifier).toSelf().inSingletonScope();
});
diff --git a/packages/core/src/node/backend-application.ts b/packages/core/src/node/backend-application.ts
index 8e50774a19181..83e8a0d8f638c 100644
--- a/packages/core/src/node/backend-application.ts
+++ b/packages/core/src/node/backend-application.ts
@@ -37,6 +37,7 @@ const TIMER_WARNING_THRESHOLD = 50;
const DEFAULT_PORT = environment.electron.is() ? 0 : 3000;
const DEFAULT_HOST = 'localhost';
const DEFAULT_SSL = false;
+const DEFAULT_FAST_STARTUP = false;
export const BackendApplicationServer = Symbol('BackendApplicationServer');
/**
@@ -107,6 +108,7 @@ export class BackendApplicationCliContribution implements CliContribution {
cert: string | undefined;
certkey: string | undefined;
projectPath: string;
+ fastStartup: boolean;
configure(conf: yargs.Argv): void {
conf.option('port', { alias: 'p', description: 'The port the backend server listens on.', type: 'number', default: DEFAULT_PORT });
@@ -115,6 +117,7 @@ export class BackendApplicationCliContribution implements CliContribution {
conf.option('cert', { description: 'Path to SSL certificate.', type: 'string' });
conf.option('certkey', { description: 'Path to SSL certificate key.', type: 'string' });
conf.option(APP_PROJECT_PATH, { description: 'Sets the application project directory', default: this.appProjectPath() });
+ conf.option('fastStartup', {description: 'delay plugin deployment to decrease startup time', type: 'boolean', default: DEFAULT_FAST_STARTUP});
}
setArguments(args: yargs.Arguments): void {
@@ -124,6 +127,7 @@ export class BackendApplicationCliContribution implements CliContribution {
this.cert = args.cert as string;
this.certkey = args.certkey as string;
this.projectPath = args[APP_PROJECT_PATH] as string;
+ this.fastStartup = args['fastStartup'] as boolean;
}
protected appProjectPath(): string {
diff --git a/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts b/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts
index 1a0adc3f22377..6a53ff74df2b7 100644
--- a/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts
+++ b/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts
@@ -14,21 +14,30 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
-import { BackendApplicationContribution } from '@theia/core/lib/node';
+import { BackendApplicationCliContribution, BackendApplicationContribution } from '@theia/core/lib/node';
+import { ClientConnectionNotifier } from '@theia/core/lib/common';
import { injectable, inject } from '@theia/core/shared/inversify';
import { PluginDeployer } from '../../common/plugin-protocol';
-import { ILogger } from '@theia/core';
@injectable()
export class PluginDeployerContribution implements BackendApplicationContribution {
- @inject(ILogger)
- protected readonly logger: ILogger;
-
@inject(PluginDeployer)
protected pluginDeployer: PluginDeployer;
+ @inject(ClientConnectionNotifier)
+ protected readonly connectionNotifier: ClientConnectionNotifier;
+
+ @inject(BackendApplicationCliContribution)
+ protected readonly cliParams: BackendApplicationCliContribution;
+
initialize(): void {
- this.pluginDeployer.start();
+ if (this.cliParams.fastStartup) {
+ this.connectionNotifier.connectionEvent.on(ClientConnectionNotifier.CLIENT_CONNECTED, async () => {
+ this.pluginDeployer.start();
+ });
+ } else {
+ this.pluginDeployer.start();
+ }
}
}