Add internal plugins as workspaces to single package.json
Summary: We cannot just add internal plugins as workspaces to the root package.json in "sonar/desktop" as they are not open-sourced, so public build will break. Instead, I have created root package.json for internal plugins and added all internal plugins as workspaces there. This means all these plugins will use the single root yarn.lock and installation of their dependencies will be faster. This also means that plugins can declare dependencies to other local packages included into workspaces and they will be symlinked automatically. Reviewed By: mweststrate Differential Revision: D20806237 fbshipit-source-id: f8b3327166963dec7da8ac74079682aebe4527e1
This commit is contained in:
committed by
Facebook GitHub Bot
parent
bcc133026e
commit
452c52c291
@@ -20,7 +20,7 @@
|
|||||||
"ansi-to-html": "^0.6.3",
|
"ansi-to-html": "^0.6.3",
|
||||||
"async-mutex": "^0.1.3",
|
"async-mutex": "^0.1.3",
|
||||||
"chalk": "^3.0.0",
|
"chalk": "^3.0.0",
|
||||||
"codemirror": "^5.25.0",
|
"codemirror": "^5.52.2",
|
||||||
"cross-env": "^7.0.0",
|
"cross-env": "^7.0.0",
|
||||||
"dashify": "^2.0.0",
|
"dashify": "^2.0.0",
|
||||||
"decompress": "^4.2.0",
|
"decompress": "^4.2.0",
|
||||||
|
|||||||
@@ -189,7 +189,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "node scripts/prepare-watchman-config.js && yarn config set ignore-engines",
|
"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-dist": "rimraf ../dist",
|
||||||
"rm-modules": "rimraf **/*/node_modules node_modules",
|
"rm-modules": "rimraf **/*/node_modules node_modules",
|
||||||
"rm-temp": "rimraf $TMPDIR/jest* $TMPDIR/react-native-packager*",
|
"rm-temp": "rimraf $TMPDIR/jest* $TMPDIR/react-native-packager*",
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import path from 'path';
|
|||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import {spawn} from 'promisify-child-process';
|
import {spawn} from 'promisify-child-process';
|
||||||
import recursiveReaddir from 'recursive-readdir';
|
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 {
|
import {
|
||||||
appDir,
|
appDir,
|
||||||
staticDir,
|
staticDir,
|
||||||
@@ -106,12 +107,10 @@ export async function compileHeadless(buildFolder: string) {
|
|||||||
const watchFolders = [
|
const watchFolders = [
|
||||||
headlessDir,
|
headlessDir,
|
||||||
...(await getWatchFolders(staticDir)),
|
...(await getWatchFolders(staticDir)),
|
||||||
...(await getWatchFolders(appDir)),
|
...(await getAppWatchFolders()),
|
||||||
path.join(pluginsDir, 'navigation'),
|
]
|
||||||
path.join(pluginsDir, 'fb', 'layout', 'sidebar_extensions'),
|
.filter((value, index, self) => self.indexOf(value) === index)
|
||||||
path.join(pluginsDir, 'fb', 'mobileconfig'),
|
.filter(fs.pathExistsSync);
|
||||||
path.join(pluginsDir, 'fb', 'watch'),
|
|
||||||
].filter(fs.pathExistsSync);
|
|
||||||
try {
|
try {
|
||||||
await compile(
|
await compile(
|
||||||
buildFolder,
|
buildFolder,
|
||||||
@@ -127,13 +126,7 @@ export async function compileHeadless(buildFolder: string) {
|
|||||||
|
|
||||||
export async function compileRenderer(buildFolder: string) {
|
export async function compileRenderer(buildFolder: string) {
|
||||||
console.log(`⚙️ Compiling renderer bundle...`);
|
console.log(`⚙️ Compiling renderer bundle...`);
|
||||||
const watchFolders = [
|
const watchFolders = await getAppWatchFolders();
|
||||||
...(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);
|
|
||||||
try {
|
try {
|
||||||
await compile(
|
await compile(
|
||||||
buildFolder,
|
buildFolder,
|
||||||
|
|||||||
36
desktop/scripts/get-app-watch-folders.ts
Normal file
36
desktop/scripts/get-app-watch-folders.ts
Normal file
@@ -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);
|
||||||
|
}
|
||||||
@@ -22,8 +22,8 @@ import {compileMain} from './build-utils';
|
|||||||
import Watchman from '../static/watchman';
|
import Watchman from '../static/watchman';
|
||||||
import Metro from 'metro';
|
import Metro from 'metro';
|
||||||
import MetroResolver from 'metro-resolver';
|
import MetroResolver from 'metro-resolver';
|
||||||
import {default as getWatchFolders} from '../static/get-watch-folders';
|
import getAppWatchFolders from './get-app-watch-folders';
|
||||||
import {staticDir, pluginsDir, appDir, babelTransformationsDir} from './paths';
|
import {staticDir, appDir, babelTransformationsDir} from './paths';
|
||||||
import isFB from './isFB';
|
import isFB from './isFB';
|
||||||
|
|
||||||
const ansiToHtmlConverter = new AnsiToHtmlConverter();
|
const ansiToHtmlConverter = new AnsiToHtmlConverter();
|
||||||
@@ -81,13 +81,7 @@ function launchElectron({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function startMetroServer(app: Express) {
|
async function startMetroServer(app: Express) {
|
||||||
const watchFolders = [
|
const watchFolders = await getAppWatchFolders();
|
||||||
...(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 metroBundlerServer = await Metro.runMetro({
|
const metroBundlerServer = await Metro.runMetro({
|
||||||
projectRoot: appDir,
|
projectRoot: appDir,
|
||||||
watchFolders,
|
watchFolders,
|
||||||
|
|||||||
20
desktop/scripts/yarn-install-fb-plugins.ts
Normal file
20
desktop/scripts/yarn-install-fb-plugins.ts
Normal file
@@ -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',
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -209,7 +209,11 @@ function entryPointForPluginFolder(pluginPath: string) {
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
if (packageJSON) {
|
if (packageJSON) {
|
||||||
try {
|
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 = {
|
const plugin: PluginInfo = {
|
||||||
manifest: pkg,
|
manifest: pkg,
|
||||||
name: pkg.name,
|
name: pkg.name,
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export default async (packageDir: string) => {
|
export default async (packageDir: string): Promise<string[]> => {
|
||||||
|
if (!(await fs.pathExists(packageDir))) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const watchDirs: string[] = [packageDir];
|
const watchDirs: string[] = [packageDir];
|
||||||
const pkg = await fs.readJson(path.join(packageDir, 'package.json'));
|
const pkg = await fs.readJson(path.join(packageDir, 'package.json'));
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@@ -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"
|
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||||
|
|
||||||
codemirror@^5.25.0:
|
codemirror@^5.52.2:
|
||||||
version "5.52.2"
|
version "5.52.2"
|
||||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.52.2.tgz#c29e1f7179f85eb0dd17c0586fa810e4838ff584"
|
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.52.2.tgz#c29e1f7179f85eb0dd17c0586fa810e4838ff584"
|
||||||
integrity sha512-WCGCixNUck2HGvY8/ZNI1jYfxPG5cRHv0VjmWuNzbtCLz8qYA5d+je4QhSSCtCaagyeOwMi/HmmPTjBgiTm2lQ==
|
integrity sha512-WCGCixNUck2HGvY8/ZNI1jYfxPG5cRHv0VjmWuNzbtCLz8qYA5d+je4QhSSCtCaagyeOwMi/HmmPTjBgiTm2lQ==
|
||||||
|
|||||||
Reference in New Issue
Block a user