Files
flipper/desktop/flipper-ui-browser/src/index.tsx
Lorenzo Blasa fecaa8d974 Back out "Use isPWA utility function instead"
Summary:
Original commit changeset: 6bc0c942b3d9

Original Phabricator Diff: D50885337

There's an issue with the import, same reason we do:

```
require('flipper-ui-core').startFlipperDesktop(flipperServer);
```

Reviewed By: aigoncharov

Differential Revision: D50926125

fbshipit-source-id: 04e1b920bcecab9f245924907637b36dac312f1f
2023-11-02 04:28:14 -07:00

256 lines
7.3 KiB
TypeScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import {
getLogger,
getStringFromErrorLike,
setLoggerInstance,
} from 'flipper-common';
import {init as initLogger} from './fb-stubs/Logger';
import {initializeRenderHost} from './initializeRenderHost';
import {createFlipperServer, FlipperServerState} from 'flipper-server-client';
const loadingContainer = document.getElementById('loading');
if (loadingContainer) {
loadingContainer.innerText = 'Loading...';
}
let cachedFile: {name: string; data: string} | undefined;
let cachedDeepLinkURL: string | undefined;
const logger = initLogger();
async function start() {
/**
* The following is used to ensure only one instance of Flipper is running at a time.
* The event will not be fired for the current tab.
*/
window.addEventListener('storage', function (event) {
if (event.key === 'flipper-kill-window') {
window.close();
}
});
// @ts-ignore
electronRequire = function (path: string) {
console.error(
`[decapitate] Tried to electronRequire ${path}, this module is not available in the browser and will be stubbed`,
);
return {
default: {},
};
};
setLoggerInstance(logger);
const params = new URL(location.href).searchParams;
const tokenProvider = async () => {
const providerParams = new URL(location.href).searchParams;
let token = providerParams.get('token');
if (!token) {
console.info(
'[flipper-client][ui-browser] Get token from manifest instead',
);
try {
const manifestResponse = await fetch('manifest.json');
const manifest = await manifestResponse.json();
token = manifest.token;
} catch (e) {
console.warn(
'[flipper-client][ui-browser] Failed to get token from manifest. Error:',
e.message,
);
}
}
getLogger().info(
'[flipper-client][ui-browser] Token is available: ',
token?.length != 0,
);
return token;
};
const openPlugin = params.get('open-plugin');
if (openPlugin) {
function removePrefix(input: string, prefix: string): string {
const regex = new RegExp(`^${prefix}+`);
return input.replace(regex, '');
}
const url = new URL(openPlugin);
const maybeParams = removePrefix(url.pathname, '/');
const params = new URLSearchParams(maybeParams);
const deeplinkURL = new URL('flipper://open-plugin');
deeplinkURL.search = params.toString();
cachedDeepLinkURL = deeplinkURL.toString();
}
getLogger().info('[flipper-client][ui-browser] Create WS client');
const flipperServer = await createFlipperServer(
location.hostname,
parseInt(location.port, 10),
tokenProvider,
(state: FlipperServerState) => {
switch (state) {
case FlipperServerState.CONNECTING:
getLogger().info('[flipper-client] Connecting to server');
window.flipperShowMessage?.('Connecting to server...');
break;
case FlipperServerState.CONNECTED:
getLogger().info(
'[flipper-client] Connection established with server',
);
window.flipperHideMessage?.();
break;
case FlipperServerState.DISCONNECTED:
getLogger().info('[flipper-client] Disconnected from server');
window.flipperShowMessage?.('Waiting for server...');
break;
}
},
);
getLogger().info('[flipper-client][ui-browser] WS client connected');
flipperServer.on('server-log', (logEntry) => {
getLogger()[logEntry.type](
`[${logEntry.namespace}] (${new Date(
logEntry.time,
).toLocaleTimeString()}): ${logEntry.msg}`,
);
});
getLogger().info(
'[flipper-client][ui-browser] Waiting for server connection',
);
await flipperServer.connect();
getLogger().info(
'[flipper-client][ui-browser] Connected to server, get configuration',
);
const flipperServerConfig = await flipperServer.exec('get-config');
getLogger().info(
'[flipper-client][ui-browser] Configuration obtained, initialise render host',
);
initializeRenderHost(flipperServer, flipperServerConfig);
initializePWA();
// @ts-ignore
// eslint-disable-next-line import/no-commonjs
require('flipper-ui-core').startFlipperDesktop(flipperServer);
window.flipperHideMessage?.();
/**
* At this stage, the current client has established a connection with the server.
* So, it is safe to 'set' into local storage so that other clients close.
*/
localStorage.setItem('flipper-kill-window', Date.now().toString());
getLogger().info('[flipper-client][ui-browser] UI initialised');
logger.track('success-rate', 'flipper-ui-browser-started', {value: 1});
}
start().catch((e) => {
getLogger().error('Failed to start flipper-ui-browser', e);
logger.track('success-rate', 'flipper-ui-browser-started', {
value: 0,
error: getStringFromErrorLike(e),
pwa: window.matchMedia('(display-mode: standalone)').matches,
});
window.flipperShowMessage?.('Failed to start UI with error: ' + e);
});
async function initializePWA() {
getLogger().info('[PWA] Initialization');
let rehydrated = false;
const openFileIfAny = () => {
if (!cachedFile || !rehydrated) {
return;
}
window.dispatchEvent(
new CustomEvent('open-flipper-file', {
detail: [cachedFile.name, cachedFile.data],
}),
);
cachedFile = undefined;
};
const openURLIfAny = () => {
if (!cachedDeepLinkURL || !rehydrated) {
return;
}
window.dispatchEvent(
new CustomEvent('flipper-protocol-handler', {
detail: [cachedDeepLinkURL],
}),
);
cachedDeepLinkURL = undefined;
};
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/service-worker.js')
.then(() => {
getLogger().info('[PWA] Service Worker has been registered');
})
.catch((e) => {
getLogger().error('[PWA] failed to register Service Worker', e);
});
}
if ('launchQueue' in window) {
getLogger().debug('[PWA] File Handling API is supported');
// @ts-ignore
window.launchQueue.setConsumer(async (launchParams) => {
if (!launchParams || !launchParams.files) {
return;
}
getLogger().debug('[PWA] Attempt to to open a file');
for (const file of launchParams.files) {
const blob = await file.getFile();
blob.handle = file;
const data = await blob.text();
const name = file.name;
cachedFile = {name, data};
openFileIfAny();
}
});
} else {
console.warn('[PWA] File Handling API is not supported');
}
getLogger().debug('[PWA] Add before install prompt listener');
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt.
e.preventDefault();
// Stash the event so it can be triggered later.
// @ts-ignore
global.PWAppInstallationEvent = e;
getLogger().info('[PWA] Installation event has been captured');
});
window.addEventListener('storeRehydrated', () => {
getLogger().info('[PWA] Store is rehydrated');
rehydrated = true;
openFileIfAny();
openURLIfAny();
});
}