diff --git a/desktop/app/package.json b/desktop/app/package.json index dcfa4422e..09b30f60a 100644 --- a/desktop/app/package.json +++ b/desktop/app/package.json @@ -20,7 +20,7 @@ "ansi-to-html": "^0.6.3", "async-mutex": "^0.1.3", "chalk": "^3.0.0", - "codemirror": "^5.25.0", + "codemirror": "^5.52.2", "cross-env": "^7.0.0", "dashify": "^2.0.0", "decompress": "^4.2.0", diff --git a/desktop/package.json b/desktop/package.json index ca1e6cd05..0c0848f82 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -189,7 +189,7 @@ }, "scripts": { "preinstall": "node scripts/prepare-watchman-config.js && yarn config set ignore-engines", - "postinstall": "./ts-node scripts/yarn-install.ts && patch-package", + "postinstall": "patch-package && ./ts-node scripts/yarn-install-fb-plugins.ts", "rm-dist": "rimraf ../dist", "rm-modules": "rimraf **/*/node_modules node_modules", "rm-temp": "rimraf $TMPDIR/jest* $TMPDIR/react-native-packager*", diff --git a/desktop/scripts/build-utils.ts b/desktop/scripts/build-utils.ts index db6c9dcf3..7b9338710 100644 --- a/desktop/scripts/build-utils.ts +++ b/desktop/scripts/build-utils.ts @@ -15,7 +15,8 @@ import path from 'path'; import fs from 'fs-extra'; import {spawn} from 'promisify-child-process'; import recursiveReaddir from 'recursive-readdir'; -import {default as getWatchFolders} from '../static/get-watch-folders'; +import getWatchFolders from '../static/get-watch-folders'; +import getAppWatchFolders from './get-app-watch-folders'; import { appDir, staticDir, @@ -106,12 +107,10 @@ export async function compileHeadless(buildFolder: string) { const watchFolders = [ headlessDir, ...(await getWatchFolders(staticDir)), - ...(await getWatchFolders(appDir)), - path.join(pluginsDir, 'navigation'), - path.join(pluginsDir, 'fb', 'layout', 'sidebar_extensions'), - path.join(pluginsDir, 'fb', 'mobileconfig'), - path.join(pluginsDir, 'fb', 'watch'), - ].filter(fs.pathExistsSync); + ...(await getAppWatchFolders()), + ] + .filter((value, index, self) => self.indexOf(value) === index) + .filter(fs.pathExistsSync); try { await compile( buildFolder, @@ -127,13 +126,7 @@ export async function compileHeadless(buildFolder: string) { export async function compileRenderer(buildFolder: string) { console.log(`⚙️ Compiling renderer bundle...`); - const watchFolders = [ - ...(await getWatchFolders(appDir)), - path.join(pluginsDir, 'navigation'), - path.join(pluginsDir, 'fb', 'layout', 'sidebar_extensions'), - path.join(pluginsDir, 'fb', 'mobileconfig'), - path.join(pluginsDir, 'fb', 'watch'), - ].filter(fs.pathExistsSync); + const watchFolders = await getAppWatchFolders(); try { await compile( buildFolder, diff --git a/desktop/scripts/get-app-watch-folders.ts b/desktop/scripts/get-app-watch-folders.ts new file mode 100644 index 000000000..829e2ee6b --- /dev/null +++ b/desktop/scripts/get-app-watch-folders.ts @@ -0,0 +1,36 @@ +/** + * 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 + */ + +import fs from 'fs-extra'; +import path from 'path'; +import getWatchFolders from '../static/get-watch-folders'; +import {appDir, pluginsDir} from './paths'; + +/** + * Flipper references code from below plugins directly. Such directly referenced plugins + * and their dependencies should be added as watch folders so Metro bundled can resolve them. + */ +const pluginsReferencedDirectlyFromFlipper = [ + path.join(pluginsDir, 'navigation'), + path.join(pluginsDir, 'fb', 'layout', 'sidebar_extensions'), + path.join(pluginsDir, 'fb', 'mobileconfig'), + path.join(pluginsDir, 'fb', 'watch'), +]; + +export default async function getAppWatchFolders() { + const getWatchFoldersResults = await Promise.all( + [appDir, ...pluginsReferencedDirectlyFromFlipper].map((dir) => + getWatchFolders(dir), + ), + ); + const watchFolders = ([] as string[]).concat(...getWatchFoldersResults); + return watchFolders + .filter((value, index, self) => self.indexOf(value) === index) + .filter(fs.pathExistsSync); +} diff --git a/desktop/scripts/start-dev-server.ts b/desktop/scripts/start-dev-server.ts index 74c8856a6..e26144233 100644 --- a/desktop/scripts/start-dev-server.ts +++ b/desktop/scripts/start-dev-server.ts @@ -22,8 +22,8 @@ import {compileMain} from './build-utils'; import Watchman from '../static/watchman'; import Metro from 'metro'; import MetroResolver from 'metro-resolver'; -import {default as getWatchFolders} from '../static/get-watch-folders'; -import {staticDir, pluginsDir, appDir, babelTransformationsDir} from './paths'; +import getAppWatchFolders from './get-app-watch-folders'; +import {staticDir, appDir, babelTransformationsDir} from './paths'; import isFB from './isFB'; const ansiToHtmlConverter = new AnsiToHtmlConverter(); @@ -81,13 +81,7 @@ function launchElectron({ } async function startMetroServer(app: Express) { - const watchFolders = [ - ...(await getWatchFolders(appDir)), - path.join(pluginsDir, 'navigation'), - path.join(pluginsDir, 'fb', 'layout', 'sidebar_extensions'), - path.join(pluginsDir, 'fb', 'mobileconfig'), - path.join(pluginsDir, 'fb', 'watch'), - ].filter(fs.pathExistsSync); + const watchFolders = await getAppWatchFolders(); const metroBundlerServer = await Metro.runMetro({ projectRoot: appDir, watchFolders, diff --git a/desktop/scripts/yarn-install-fb-plugins.ts b/desktop/scripts/yarn-install-fb-plugins.ts new file mode 100644 index 000000000..8011ae0f3 --- /dev/null +++ b/desktop/scripts/yarn-install-fb-plugins.ts @@ -0,0 +1,20 @@ +/** + * 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 + */ + +import isFB from './isFB'; +import {execSync} from 'child_process'; +import path from 'path'; +import {pluginsDir} from './paths'; + +if (isFB) { + execSync('yarn install --mutex network:30330', { + cwd: path.join(pluginsDir, 'fb'), + stdio: 'inherit', + }); +} diff --git a/desktop/scripts/yarn-install.ts b/desktop/scripts/yarn-install.ts deleted file mode 100644 index 76503637e..000000000 --- a/desktop/scripts/yarn-install.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * 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 - */ - -import path from 'path'; -import util from 'util'; -import globImport from 'glob'; -import {exec as execImport} from 'child_process'; -const glob = util.promisify(globImport); -const exec = util.promisify(execImport); -const PACKAGES = ['plugins/fb/*', 'plugins/fb/layout/*']; -const WINDOWS = /^win/.test(process.platform); -const YARN_PATH = - process.argv.length > 2 - ? path.join(__dirname, process.argv[2]) - : 'yarn' + (WINDOWS ? '.cmd' : ''); - -Promise.all( - PACKAGES.map((pattern) => - glob(path.join(__dirname, '..', pattern, 'package.json')), - ), -) - .then(async (packages) => { - const flattenPackages = packages.reduce((acc, cv) => acc.concat(cv), []); - console.log( - `Installing dependencies for ${flattenPackages.length} plugins`, - ); - for (const pkg of flattenPackages) { - console.log(`Installing dependencies for ${pkg}...`); - // @ts-ignore - const {stderr, error} = await exec( - // This script is itself executed by yarn (as postinstall script), - // therefore another yarn instance is running, while we are trying to - // install the plugin dependencies. We are setting a different port - // for the mutex of this yarn instance to make sure, it is not blocked - // by the yarn instance which is executing this script. Otherwise this - // will cause a deadlock. - [YARN_PATH, '--mutex', 'network:30330'].join(' '), - { - cwd: pkg.replace('/package.json', ''), - }, - ); - if (stderr) { - if (error && error.code !== 0) { - console.warn(`❌ Installing dependencies for ${pkg} failed`); - throw stderr; - } - console.warn(stderr); - } - } - }) - // eslint-disable-next-line - .then(() => console.log('📦 Installed all plugin dependencies!')) - .catch((err) => { - console.error(err); - console.error('❌ Installing plugin dependencies failed.'); - process.exit(1); - }); diff --git a/desktop/static/compilePlugins.ts b/desktop/static/compilePlugins.ts index 75d7082c1..a55ad9b25 100644 --- a/desktop/static/compilePlugins.ts +++ b/desktop/static/compilePlugins.ts @@ -209,7 +209,11 @@ function entryPointForPluginFolder(pluginPath: string) { } catch (e) {} if (packageJSON) { try { - const pkg = JSON.parse(packageJSON) as PluginManifest; + const json = JSON.parse(packageJSON); + if (json.workspaces) { + return null; + } + const pkg = json as PluginManifest; const plugin: PluginInfo = { manifest: pkg, name: pkg.name, diff --git a/desktop/static/get-watch-folders.ts b/desktop/static/get-watch-folders.ts index bf8f46ded..8d9140e03 100644 --- a/desktop/static/get-watch-folders.ts +++ b/desktop/static/get-watch-folders.ts @@ -10,7 +10,10 @@ import fs from 'fs-extra'; import path from 'path'; -export default async (packageDir: string) => { +export default async (packageDir: string): Promise => { + if (!(await fs.pathExists(packageDir))) { + return []; + } const watchDirs: string[] = [packageDir]; const pkg = await fs.readJson(path.join(packageDir, 'package.json')); while (true) { diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 22d8447d2..27ffa22c7 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -3653,7 +3653,7 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -codemirror@^5.25.0: +codemirror@^5.52.2: version "5.52.2" resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.52.2.tgz#c29e1f7179f85eb0dd17c0586fa810e4838ff584" integrity sha512-WCGCixNUck2HGvY8/ZNI1jYfxPG5cRHv0VjmWuNzbtCLz8qYA5d+je4QhSSCtCaagyeOwMi/HmmPTjBgiTm2lQ==