fix(electron): do not use --require to throttle startup (#4006)

This commit is contained in:
Pavel Feldman 2020-09-29 18:01:14 -07:00 committed by GitHub
parent 6dccd2735a
commit 20b83ee0b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 13 additions and 89 deletions

View File

@ -14,7 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import { CRBrowser, CRBrowserContext } from '../chromium/crBrowser'; import { CRBrowser, CRBrowserContext } from '../chromium/crBrowser';
import { CRConnection, CRSession } from '../chromium/crConnection'; import { CRConnection, CRSession } from '../chromium/crConnection';
@ -77,17 +76,18 @@ export class ElectronApplication extends EventEmitter {
private async _onPage(page: ElectronPage) { private async _onPage(page: ElectronPage) {
// Needs to be sync. // Needs to be sync.
const windowId = ++this._lastWindowId; const windowId = ++this._lastWindowId;
// Can be async.
const handle = await this._nodeElectronHandle!.evaluateHandle(({ BrowserWindow }, windowId) => BrowserWindow.fromId(windowId), windowId).catch(e => {});
if (!handle)
return;
page.browserWindow = handle;
page._browserWindowId = windowId;
page.on(Page.Events.Close, () => { page.on(Page.Events.Close, () => {
page.browserWindow.dispose(); page.browserWindow.dispose();
this._windows.delete(page); this._windows.delete(page);
}); });
page._browserWindowId = windowId;
this._windows.add(page); this._windows.add(page);
// Below is async.
const handle = await this._nodeElectronHandle!.evaluateHandle(({ BrowserWindow }, windowId) => BrowserWindow.fromId(windowId), windowId).catch(e => {});
if (!handle)
return;
page.browserWindow = handle;
await runAbortableTask(progress => page.mainFrame()._waitForLoadState(progress, 'domcontentloaded'), page._timeoutSettings.navigationTimeout({})).catch(e => {}); // can happen after detach await runAbortableTask(progress => page.mainFrame()._waitForLoadState(progress, 'domcontentloaded'), page._timeoutSettings.navigationTimeout({})).catch(e => {}); // can happen after detach
this.emit(ElectronApplication.Events.Window, page); this.emit(ElectronApplication.Events.Window, page);
} }
@ -126,16 +126,12 @@ export class ElectronApplication extends EventEmitter {
} }
async _init() { async _init() {
this._nodeSession.once('Runtime.executionContextCreated', event => { this._nodeSession.on('Runtime.executionContextCreated', (event: any) => {
this._nodeExecutionContext = new js.ExecutionContext(new CRExecutionContext(this._nodeSession, event.context)); if (event.context.auxData && event.context.auxData.isDefault)
this._nodeExecutionContext = new js.ExecutionContext(new CRExecutionContext(this._nodeSession, event.context));
}); });
await this._nodeSession.send('Runtime.enable', {}).catch(e => {}); await this._nodeSession.send('Runtime.enable', {}).catch(e => {});
this._nodeElectronHandle = await js.evaluate(this._nodeExecutionContext!, false /* returnByValue */, () => { this._nodeElectronHandle = await js.evaluate(this._nodeExecutionContext!, false /* returnByValue */, `process.mainModule.require('electron')`);
// Resolving the race between the debugger and the boot-time script.
if ((global as any)._playwrightRun)
return (global as any)._playwrightRun();
return new Promise(f => (global as any)._playwrightRunCallback = f);
});
} }
} }
@ -151,7 +147,7 @@ export class Electron {
controller.setLogName('browser'); controller.setLogName('browser');
return controller.run(async progress => { return controller.run(async progress => {
let app: ElectronApplication | undefined = undefined; let app: ElectronApplication | undefined = undefined;
const electronArguments = ['--inspect=0', '--remote-debugging-port=0', '--require', path.join(__dirname, 'electronLoader.js'), ...args]; const electronArguments = ['--inspect=0', '--remote-debugging-port=0', ...args];
if (os.platform() === 'linux') { if (os.platform() === 'linux') {
const runningAsRoot = process.geteuid && process.geteuid() === 0; const runningAsRoot = process.geteuid && process.geteuid() === 0;
@ -171,7 +167,7 @@ export class Electron {
cwd: options.cwd, cwd: options.cwd,
tempDirectories: [], tempDirectories: [],
attemptToGracefullyClose: () => app!.close(), attemptToGracefullyClose: () => app!.close(),
onExit: (exitCode, signal) => {}, onExit: () => {},
}); });
const nodeMatch = await waitForLine(progress, launchedProcess, launchedProcess.stderr, /^Debugger listening on (ws:\/\/.*)$/); const nodeMatch = await waitForLine(progress, launchedProcess, launchedProcess.stderr, /^Debugger listening on (ws:\/\/.*)$/);

View File

@ -1,72 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as electron from 'electron';
// Electron loader is passed to Electron as --require electronLoader.js and
// defers the app ready event until remote debugging is established.
(async () => {
const app = electron.app;
const originalEmitMethod = app.emit.bind(app);
const originalIsReadyMethod = app.isReady.bind(app);
const originalWhenReadyMethod = app.whenReady.bind(app);
const deferredEmits: { event: string | symbol, args: any[] }[] = [];
let attached = false;
let isReady = false;
let readyCallback: () => void;
const readyPromise = new Promise(f => readyCallback = f);
app.isReady = () => {
if (attached)
return originalIsReadyMethod();
return isReady;
};
app.whenReady = async () => {
if (attached)
return originalWhenReadyMethod();
await readyPromise;
};
app.emit = (event: string | symbol, ...args: any[]): boolean => {
if (attached)
return originalEmitMethod(event, ...args);
deferredEmits.push({ event, args });
return true;
};
const playwrightRun = () => {
while (deferredEmits.length) {
const emit = deferredEmits.shift();
if (emit!.event === 'ready') {
isReady = true;
readyCallback();
}
originalEmitMethod(emit!.event, ...emit!.args);
}
attached = true;
return electron;
};
// Resolving the race between the debugger and the boot-time script.
if ((global as any)._playwrightRunCallback) {
(global as any)._playwrightRunCallback(playwrightRun());
return;
}
(global as any)._playwrightRun = playwrightRun;
})();