diff --git a/desktop/app/package.json b/desktop/app/package.json index 4ec4fb27c..e150d1aad 100644 --- a/desktop/app/package.json +++ b/desktop/app/package.json @@ -24,6 +24,7 @@ }, "optionalDependencies": {}, "devDependencies": { + "@types/node": "^15.12.5", "react-refresh": "^0.11.0" } } diff --git a/desktop/app/src/electron/initializeElectron.tsx b/desktop/app/src/electron/initializeElectron.tsx index 2dd1c921d..493e52750 100644 --- a/desktop/app/src/electron/initializeElectron.tsx +++ b/desktop/app/src/electron/initializeElectron.tsx @@ -179,7 +179,7 @@ export function initializeElectron( }, flipperServer, async requirePlugin(path) { - return (window as any).electronRequire(path); + return global.electronRequire(path); }, getStaticResourceUrl(relativePath): string { return ( diff --git a/desktop/flipper-server-core/package.json b/desktop/flipper-server-core/package.json index 3905029d7..e918bebed 100644 --- a/desktop/flipper-server-core/package.json +++ b/desktop/flipper-server-core/package.json @@ -39,7 +39,9 @@ "ws": "^8.2.3", "xdg-basedir": "^4.0.0" }, - "devDependencies": {}, + "devDependencies": { + "@types/node": "^15.12.5" + }, "peerDependencies": {}, "scripts": { "reset": "rimraf lib *.tsbuildinfo", diff --git a/desktop/flipper-server-core/src/plugins/PluginManager.tsx b/desktop/flipper-server-core/src/plugins/PluginManager.tsx index f9f7d7b86..0c7320848 100644 --- a/desktop/flipper-server-core/src/plugins/PluginManager.tsx +++ b/desktop/flipper-server-core/src/plugins/PluginManager.tsx @@ -45,7 +45,9 @@ const getTempDirName = promisify(tmp.dir) as ( export class PluginManager { async start() { // This needn't happen immediately and is (light) I/O work. - (window.requestIdleCallback || setImmediate)(() => { + (typeof window !== 'undefined' + ? window?.requestIdleCallback + : setImmediate)(() => { cleanupOldInstalledPluginVersions(maxInstalledPluginVersionsToKeep).catch( (err) => console.error('Failed to clean up old installed plugins:', err), diff --git a/desktop/flipper-server/package.json b/desktop/flipper-server/package.json index b2fbf8864..dc6a61454 100644 --- a/desktop/flipper-server/package.json +++ b/desktop/flipper-server/package.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@types/express": "^4.17.13", + "@types/node": "^15.12.5", "metro": "^0.66.2", "nodemon": "^2.0.15", "ts-node": "^9.1.1", @@ -32,7 +33,7 @@ "reset": "rimraf lib *.tsbuildinfo", "build": "tsc -b", "prepack": "yarn reset && yarn build", - "start": "cross-env NODE_ENV=development nodemon --watch './src/**/*.tsx' --watch '../flipper-server-core/src/**/*.tsx' --exec 'yarn build && ../ts-node src/index.tsx'" + "start": "cross-env NODE_ENV=development nodemon --ext 'tsx' --watch './src/' --watch '../flipper-server-core/src/' --exec 'yarn build && ../ts-node src/index.tsx'" }, "files": [ "lib/**/*" diff --git a/desktop/flipper-server/src/index.tsx b/desktop/flipper-server/src/index.tsx index 46cecccf0..e79e927a2 100644 --- a/desktop/flipper-server/src/index.tsx +++ b/desktop/flipper-server/src/index.tsx @@ -39,7 +39,8 @@ async function start() { start() .then(() => { console.log( - `Flipper DEV server started at http://localhost:${PORT}/index.web.dev.html`, + 'Flipper DEV server started at ' + + chalk.green(chalk.bold(`http://localhost:${PORT}/index.web.dev.html`)), ); }) .catch((e) => { diff --git a/desktop/flipper-server/src/startWebServerDev.tsx b/desktop/flipper-server/src/startWebServerDev.tsx index 6229b67eb..8cb7de413 100644 --- a/desktop/flipper-server/src/startWebServerDev.tsx +++ b/desktop/flipper-server/src/startWebServerDev.tsx @@ -16,6 +16,9 @@ import socketio from 'socket.io'; import {getWatchFolders} from 'flipper-pkg-lib'; import Metro from 'metro'; import pFilter from 'p-filter'; +// provided by Metro +// eslint-disable-next-line +import MetroResolver from 'metro-resolver'; const uiSourceDirs = [ 'flipper-ui-browser', @@ -24,6 +27,53 @@ const uiSourceDirs = [ 'flipper-common', ]; +const stubModules = new Set([ + 'fs', + 'path', + 'crypto', + 'process', + 'os', + 'util', + 'child_process', + 'assert', + 'adbkit', // TODO: factor out! + 'zlib', + 'events', + 'fs-extra', + 'archiver', + 'graceful-fs', + 'stream', + 'url', + 'node-fetch', + 'net', + 'vm', + 'debug', + 'lockfile', + 'constants', + 'https', + 'plugin-lib', // TODO: we only want the types? + 'flipper-plugin-lib', + 'tar', + 'minipass', + 'live-plugin-manager', + 'decompress-tar', + 'readable-stream', + 'archiver-utils', + 'metro', + 'decompress', + 'temp', + 'tmp', + 'promisify-child-process', + 'jsdom', + 'extract-zip', + 'yauzl', + 'fd-slicer', + 'envinfo', + 'bser', + 'fb-watchman', + // TODO fix me +]); + // This file is heavily inspired by scripts/start-dev-server.ts! export async function startWebServerDev( app: Express, @@ -84,8 +134,27 @@ async function startMetroServer( resolver: { ...baseConfig.resolver, resolverMainFields: ['flipperBundlerEntry', 'browser', 'module', 'main'], - blacklistRE: /\.native\.js$/, + blacklistRE: [/\.native\.js$/], sourceExts: ['js', 'jsx', 'ts', 'tsx', 'json', 'mjs', 'cjs'], + resolveRequest(context: any, moduleName: string, ...rest: any[]) { + if (stubModules.has(moduleName)) { + // console.warn("Found reference to ", moduleName) + return { + type: 'empty', + }; + } + // if (moduleName.includes('pluginPaths')) { + // console.error('got ' + moduleName, rest); + // } + return MetroResolver.resolve( + { + ...context, + resolveRequest: null, + }, + moduleName, + ...rest, + ); + }, }, watch: true, // only needed when medling with babel transforms diff --git a/desktop/flipper-ui-browser/src/global.ts b/desktop/flipper-ui-browser/src/global.ts index cdf2b8b5b..54b3f5d59 100644 --- a/desktop/flipper-ui-browser/src/global.ts +++ b/desktop/flipper-ui-browser/src/global.ts @@ -7,7 +7,7 @@ * @format */ -import {RenderHost} from 'flipper-ui-core'; +import type {RenderHost} from 'flipper-ui-core'; declare global { interface Window { diff --git a/desktop/flipper-ui-browser/src/index.tsx b/desktop/flipper-ui-browser/src/index.tsx index 3456edbd0..acd14bdb7 100644 --- a/desktop/flipper-ui-browser/src/index.tsx +++ b/desktop/flipper-ui-browser/src/index.tsx @@ -14,6 +14,13 @@ import {createFlipperServer} from './flipperServerConnection'; document.getElementById('root')!.innerText = 'flipper-ui-browser started'; async function start() { + (global as any).electronRequire = function (path: string) { + console.error( + `[decapitate] Tried to electronRequire ${path}, this module is not available in the browser and will be stubbed`, + ); + return {}; + }; + const logger = createDelegatedLogger(); setLoggerInstance(logger); @@ -28,10 +35,11 @@ async function start() { // before starting the rest of the Flipper process. // This prevent issues where the render host is referred at module initialisation level, // but not set yet, which might happen when using normal imports. - // eslint-disable-next-line import/no-commonjs - // TODO: replace + // TODO: remove window.flipperShowError?.('Connected to Flipper Server successfully'); - // TODO: require('flipper-ui-core').startFlipperDesktop(flipperServer); + // eslint-disable-next-line import/no-commonjs + require('flipper-ui-core').startFlipperDesktop(flipperServer); + window.flipperHideError?.(); } start().catch((e) => { diff --git a/desktop/flipper-ui-browser/src/initializeRenderHost.tsx b/desktop/flipper-ui-browser/src/initializeRenderHost.tsx index 8751e7932..816aa95e3 100644 --- a/desktop/flipper-ui-browser/src/initializeRenderHost.tsx +++ b/desktop/flipper-ui-browser/src/initializeRenderHost.tsx @@ -8,7 +8,7 @@ */ import {FlipperServer, FlipperServerConfig} from 'flipper-common'; -import {getRenderHostInstance, RenderHost} from 'flipper-ui-core'; +import {RenderHost} from 'flipper-ui-core'; export function initializeRenderHost( flipperServer: FlipperServer, @@ -63,10 +63,7 @@ export function initializeRenderHost( flipperServer, async requirePlugin(path) { // TODO: use `await import(path)`? - const source = await getRenderHostInstance().flipperServer.exec( - 'plugin-source', - path, - ); + const source = await flipperServer.exec('plugin-source', path); // eslint-disable-next-line no-eval return eval(source); }, diff --git a/desktop/flipper-ui-core/package.json b/desktop/flipper-ui-core/package.json index 0c9770ced..78be73f92 100644 --- a/desktop/flipper-ui-core/package.json +++ b/desktop/flipper-ui-core/package.json @@ -18,7 +18,6 @@ "@types/archiver": "^5.1.1", "@types/uuid": "^8.3.1", "adbkit": "^2.11.1", - "adbkit-logcat": "^2.0.1", "antd": "4.16.8", "archiver": "^5.0.2", "async-mutex": "^0.3.2", diff --git a/desktop/flipper-ui-core/src/global.ts b/desktop/flipper-ui-core/src/global.ts index 188b501f3..5d5c06c31 100644 --- a/desktop/flipper-ui-core/src/global.ts +++ b/desktop/flipper-ui-core/src/global.ts @@ -20,10 +20,6 @@ declare global { | undefined | (StoreEnhancerStoreCreator & StoreEnhancerStateSanitizer); - Flipper: { - init: () => void; - }; - FlipperRenderHostInstance: RenderHost; } } diff --git a/desktop/flipper-ui-core/src/utils/fbEmployee.tsx b/desktop/flipper-ui-core/src/utils/fbEmployee.tsx index 8dbc644b6..c1bd3df1e 100644 --- a/desktop/flipper-ui-core/src/utils/fbEmployee.tsx +++ b/desktop/flipper-ui-core/src/utils/fbEmployee.tsx @@ -9,20 +9,21 @@ import util from 'util'; import {exec as execImport} from 'child_process'; -const exec = util.promisify(execImport); const cmd = 'klist --json'; const endWith = '@THEFACEBOOK.COM'; export async function isFBEmployee(): Promise { - return exec(cmd).then( - (stdobj: {stderr: string; stdout: string}) => { - const principal = String(JSON.parse(stdobj.stdout).principal); + return util + .promisify(execImport)(cmd) + .then( + (stdobj: {stderr: string; stdout: string}) => { + const principal = String(JSON.parse(stdobj.stdout).principal); - return principal.endsWith(endWith); - }, - (_err: Error) => { - return false; - }, - ); + return principal.endsWith(endWith); + }, + (_err: Error) => { + return false; + }, + ); } diff --git a/desktop/package.json b/desktop/package.json index 69a927869..e9f771c86 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -95,7 +95,6 @@ "@types/lodash.debounce": "^4.0.6", "@types/mkdirp": "^1.0.2", "@types/mock-fs": "^4.13.1", - "@types/node": "^15.12.5", "@types/npm-packlist": "^1.1.2", "@types/promise-retry": "^1.1.3", "@types/react": "17.0.34", @@ -234,7 +233,7 @@ "fix": "eslint . --fix --ext .js,.ts,.tsx", "lint": "yarn lint:eslint && yarn lint:tsc && yarn tsc-plugins", "lint:eslint": "eslint . --ext .js,.ts,.tsx", - "lint:tsc": "tsc --noemit", + "lint:tsc": "tsc -p tsc-root/tsconfig.json --noemit", "list-plugins": "./ts-node scripts/list-plugins.ts", "open-dist": "open ../dist/mac/Flipper.app --args --launcher=false --inspect=9229", "postinstall": "patch-package && ./ts-node scripts/gen-type-index.ts && yarn --cwd plugins install --mutex network:30331 && yarn build:tsc && ./ts-node scripts/generate-plugin-entry-points.ts && yarn build:themes", diff --git a/desktop/plugin-lib/src/pluginInstaller.ts b/desktop/plugin-lib/src/pluginInstaller.ts index 9d43f5786..0ab96bdae 100644 --- a/desktop/plugin-lib/src/pluginInstaller.ts +++ b/desktop/plugin-lib/src/pluginInstaller.ts @@ -32,8 +32,6 @@ import pmap from 'p-map'; import semver from 'semver'; import {notNull} from './typeUtils'; -const getTmpDir = promisify(tmp.dir) as () => Promise; - function providePluginManagerNoDependencies(): PM { return new PM({ignoredDependencies: [/.*/]}); } @@ -43,7 +41,7 @@ async function installPluginFromTempDir( ): Promise { const pluginDetails = await getInstalledPluginDetails(sourceDir); const {name, version} = pluginDetails; - const backupDir = path.join(await getTmpDir(), `${name}-${version}`); + const backupDir = path.join(await promisify(tmp.dir)(), `${name}-${version}`); const destinationDir = getPluginVersionInstallationDir(name, version); if (pluginDetails.specVersion == 1) { @@ -99,7 +97,7 @@ export async function getInstalledPlugin( } export async function installPluginFromNpm(name: string) { - const tmpDir = await getTmpDir(); + const tmpDir = await promisify(tmp.dir)(); try { await fs.ensureDir(tmpDir); const plugManNoDep = providePluginManagerNoDependencies(); @@ -118,7 +116,7 @@ export async function installPluginFromNpm(name: string) { export async function installPluginFromFile( packagePath: string, ): Promise { - const tmpDir = await getTmpDir(); + const tmpDir = await promisify(tmp.dir)(); try { const files = await decompress(packagePath, tmpDir, { plugins: [decompressTargz(), decompressUnzip()], diff --git a/desktop/plugins/public/reactdevtools/index.tsx b/desktop/plugins/public/reactdevtools/index.tsx index 7adcc42b3..8dc2fab99 100644 --- a/desktop/plugins/public/reactdevtools/index.tsx +++ b/desktop/plugins/public/reactdevtools/index.tsx @@ -92,7 +92,9 @@ export function devicePlugin(client: DevicePluginClient) { let metroReloadAttempts = 0; function getGlobalDevToolsModule(): ReactDevToolsStandaloneType { - const required = global.electronRequire(globalDevToolsPath.get()!).default; + const required = (global as any).electronRequire( + globalDevToolsPath.get()!, + ).default; return required.default ?? required; } diff --git a/desktop/static/index.web.dev.html b/desktop/static/index.web.dev.html index 1be12bf67..29f370150 100644 --- a/desktop/static/index.web.dev.html +++ b/desktop/static/index.web.dev.html @@ -63,11 +63,6 @@ (function() { // FIXME: needed to make Metro work window.global = window; - global.electronRequire = function(path) { - console.error("[decapitate] Tried to electronRequire: " + path); - return {}; - }; - let suppressErrors = false; const socket = io(location.origin); @@ -81,6 +76,7 @@ suppressErrors = true; }); + function openError(text) { if (suppressErrors) { return; @@ -89,6 +85,7 @@ const box = document.querySelector('.__infinity-dev-box-error'); box.removeAttribute('hidden'); box.textContent = text; + box.appendChild(closeButton); } window.flipperShowError = openError; window.flipperHideError = () => { @@ -96,6 +93,10 @@ box.setAttribute('hidden', true); } + const closeButton = document.createElement('button'); + closeButton.addEventListener('click', window.flipperHideError); + closeButton.textContent = 'X'; + // load correct theme (n.b. this doesn't handle system value specifically, will assume light in such cases) try { if (window.flipperConfig.theme === 'dark') { diff --git a/desktop/types/flipperGlobals.d.ts b/desktop/types/flipperGlobals.d.ts new file mode 100644 index 000000000..278d88cda --- /dev/null +++ b/desktop/types/flipperGlobals.d.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +declare const __REVISION__: string | undefined; +declare const __VERSION__: string; +declare const electronRequire: { + (name: string): any; + resolve: (module: string) => string; + cache: {[module: string]: any}; +}; diff --git a/desktop/types/index.d.ts b/desktop/types/index.d.ts index 7e73a0b7b..4091692b7 100644 --- a/desktop/types/index.d.ts +++ b/desktop/types/index.d.ts @@ -16,6 +16,7 @@ /// /// /// +/// /// /// /// diff --git a/desktop/types/nodejs.d.ts b/desktop/types/nodejs.d.ts index 80251e075..4f741e6dd 100644 --- a/desktop/types/nodejs.d.ts +++ b/desktop/types/nodejs.d.ts @@ -9,13 +9,6 @@ declare module NodeJS { interface Global { - __REVISION__: string | undefined; - __VERSION__: string; - electronRequire: { - (name: string): any; - resolve: (module: string) => string; - cache: {[module: string]: any}; - }; window: Window | undefined; WebSocket: any; fetch: any;