Start FlipperServerImpl as part of flipper-server
Summary: The previous started up a dev / web server for bundling in flipper-server, this diff starts the flipper server itself, so that we can connect the client to it (done in next diffs) Reviewed By: passy, aigoncharov Differential Revision: D32627390 fbshipit-source-id: b48de20f076e1e13842368d16a090708d533b69e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
0dfc73da93
commit
1308edc790
@@ -25,7 +25,6 @@ import {
|
|||||||
import type {RenderHost} from 'flipper-ui-core';
|
import type {RenderHost} from 'flipper-ui-core';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import {setupMenuBar} from './setupMenuBar';
|
import {setupMenuBar} from './setupMenuBar';
|
||||||
import os from 'os';
|
|
||||||
import {FlipperServer, FlipperServerConfig} from 'flipper-common';
|
import {FlipperServer, FlipperServerConfig} from 'flipper-common';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -36,15 +35,6 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
|
|
||||||
// By default Node.JS has its internal certificate storage and doesn't use
|
|
||||||
// the system store. Because of this, it's impossible to access ondemand / devserver
|
|
||||||
// which are signed using some internal self-issued FB certificates. These certificates
|
|
||||||
// are automatically installed to MacOS system store on FB machines, so here we're using
|
|
||||||
// this "mac-ca" library to load them into Node.JS.
|
|
||||||
global.electronRequire('mac-ca');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initializeElectron(
|
export function initializeElectron(
|
||||||
flipperServer: FlipperServer,
|
flipperServer: FlipperServer,
|
||||||
flipperServerConfig: FlipperServerConfig,
|
flipperServerConfig: FlipperServerConfig,
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export type FlipperServerCommands = {
|
|||||||
'keychain-unset': (service: string) => Promise<void>;
|
'keychain-unset': (service: string) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ENVIRONMENT_VARIABLES =
|
export type ENVIRONMENT_VARIABLES =
|
||||||
| 'NODE_ENV'
|
| 'NODE_ENV'
|
||||||
| 'DEV_SERVER_URL'
|
| 'DEV_SERVER_URL'
|
||||||
| 'CONFIG'
|
| 'CONFIG'
|
||||||
|
|||||||
@@ -12,8 +12,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"express": "^4.15.2",
|
"express": "^4.15.2",
|
||||||
|
"flipper-common": "0.0.0",
|
||||||
"flipper-pkg-lib": "0.0.0",
|
"flipper-pkg-lib": "0.0.0",
|
||||||
|
"flipper-server-core": "0.0.0",
|
||||||
"fs-extra": "^9.0.0",
|
"fs-extra": "^9.0.0",
|
||||||
|
"mac-ca": "^1.0.6",
|
||||||
"p-filter": "^2.1.0",
|
"p-filter": "^2.1.0",
|
||||||
"socket.io": "^4.3.1"
|
"socket.io": "^4.3.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,9 +11,35 @@
|
|||||||
// needs to be come independently runnable, prebundled, distributed, etc!
|
// needs to be come independently runnable, prebundled, distributed, etc!
|
||||||
// in future require conditionally
|
// in future require conditionally
|
||||||
import {startWebServerDev} from './startWebServerDev';
|
import {startWebServerDev} from './startWebServerDev';
|
||||||
|
import {startFlipperServer} from './startFlipperServer';
|
||||||
|
import {startBaseServer} from './startBaseServer';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
startWebServerDev().catch((e) => {
|
const PORT = 52342;
|
||||||
|
const rootDir = path.resolve(__dirname, '..', '..');
|
||||||
|
const staticDir = path.join(rootDir, 'static');
|
||||||
|
|
||||||
|
async function start() {
|
||||||
|
const {app, server, socket} = await startBaseServer({
|
||||||
|
port: PORT,
|
||||||
|
staticDir,
|
||||||
|
entry: 'index.web.dev.html',
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
startFlipperServer(rootDir, staticDir),
|
||||||
|
startWebServerDev(app, server, socket, rootDir),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
start()
|
||||||
|
.then(() => {
|
||||||
|
console.log(
|
||||||
|
`Flipper DEV server started at http://localhost:${PORT}/index.web.dev.html`,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
console.error(chalk.red('Server error: '), e);
|
console.error(chalk.red('Server error: '), e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
95
desktop/flipper-server/src/startBaseServer.tsx
Normal file
95
desktop/flipper-server/src/startBaseServer.tsx
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* 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 chalk from 'chalk';
|
||||||
|
import express, {Express} from 'express';
|
||||||
|
import http from 'http';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import socketio from 'socket.io';
|
||||||
|
import {hostname} from 'os';
|
||||||
|
|
||||||
|
type Config = {
|
||||||
|
port: number;
|
||||||
|
staticDir: string;
|
||||||
|
entry: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function startBaseServer(config: Config): Promise<{
|
||||||
|
app: Express;
|
||||||
|
server: http.Server;
|
||||||
|
socket: socketio.Server;
|
||||||
|
}> {
|
||||||
|
checkDevServer();
|
||||||
|
const {app, server} = await startAssetServer(config);
|
||||||
|
const socket = addWebsocket(server);
|
||||||
|
return {
|
||||||
|
app,
|
||||||
|
server,
|
||||||
|
socket,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function startAssetServer(
|
||||||
|
config: Config,
|
||||||
|
): Promise<{app: Express; server: http.Server}> {
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use((_req, res, next) => {
|
||||||
|
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
|
||||||
|
res.header('Expires', '-1');
|
||||||
|
res.header('Pragma', 'no-cache');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/', (_req, res) => {
|
||||||
|
fs.readFile(path.join(config.staticDir, config.entry), (_err, content) => {
|
||||||
|
res.end(content);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(express.static(config.staticDir));
|
||||||
|
|
||||||
|
const server = http.createServer(app);
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
server.listen(config.port, 'localhost', () => resolve({app, server}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWebsocket(server: http.Server) {
|
||||||
|
const io = new socketio.Server(server); // 3.1.0 socket.io doesn't have type definitions
|
||||||
|
|
||||||
|
io.on('connection', (client) => {
|
||||||
|
console.log(chalk.green(`Client connected ${client.id}`));
|
||||||
|
});
|
||||||
|
|
||||||
|
return io;
|
||||||
|
}
|
||||||
|
|
||||||
|
function looksLikeDevServer(): boolean {
|
||||||
|
const hn = hostname();
|
||||||
|
if (/^devvm.*\.facebook\.com$/.test(hn)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (hn.endsWith('.od.fbinfra.net')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDevServer() {
|
||||||
|
if (looksLikeDevServer()) {
|
||||||
|
console.log(
|
||||||
|
chalk.red(
|
||||||
|
`✖ It looks like you're trying to start Flipper on your OnDemand or DevServer, which is not supported. Please run this in a local checkout on your laptop or desktop instead.`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
120
desktop/flipper-server/src/startFlipperServer.tsx
Normal file
120
desktop/flipper-server/src/startFlipperServer.tsx
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* 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 os from 'os';
|
||||||
|
import {
|
||||||
|
FlipperServerImpl,
|
||||||
|
getGatekeepers,
|
||||||
|
loadLauncherSettings,
|
||||||
|
loadProcessConfig,
|
||||||
|
loadSettings,
|
||||||
|
} from 'flipper-server-core';
|
||||||
|
import {
|
||||||
|
ENVIRONMENT_VARIABLES,
|
||||||
|
isTest,
|
||||||
|
Logger,
|
||||||
|
setLoggerInstance,
|
||||||
|
} from 'flipper-common';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
export async function startFlipperServer(rootDir: string, staticDir: string) {
|
||||||
|
if (os.platform() === 'darwin') {
|
||||||
|
// By default Node.JS has its internal certificate storage and doesn't use
|
||||||
|
// the system store. Because of this, it's impossible to access ondemand / devserver
|
||||||
|
// which are signed using some internal self-issued FB certificates. These certificates
|
||||||
|
// are automatically installed to MacOS system store on FB machines, so here we're using
|
||||||
|
// this "mac-ca" library to load them into Node.JS.
|
||||||
|
require('mac-ca');
|
||||||
|
}
|
||||||
|
|
||||||
|
const execPath = process.execPath;
|
||||||
|
const appPath = rootDir;
|
||||||
|
const isProduction =
|
||||||
|
process.env.NODE_ENV !== 'development' && process.env.NODE_ENV !== 'test';
|
||||||
|
const env = process.env;
|
||||||
|
let desktopPath = path.resolve(os.homedir(), 'Desktop');
|
||||||
|
|
||||||
|
// eslint-disable-next-line node/no-sync
|
||||||
|
if (!fs.existsSync(desktopPath)) {
|
||||||
|
console.warn('Failed to find desktop path, falling back to homedir');
|
||||||
|
desktopPath = os.homedir();
|
||||||
|
}
|
||||||
|
|
||||||
|
const logger = createLogger();
|
||||||
|
setLoggerInstance(logger);
|
||||||
|
|
||||||
|
let keytar: any = undefined;
|
||||||
|
try {
|
||||||
|
if (!isTest()) {
|
||||||
|
keytar = require(path.join(
|
||||||
|
staticDir,
|
||||||
|
'native-modules',
|
||||||
|
`keytar-${process.platform}.node`,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load keytar:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const envVars: Partial<Record<ENVIRONMENT_VARIABLES, string | undefined>> =
|
||||||
|
Object.fromEntries(
|
||||||
|
([] as ENVIRONMENT_VARIABLES[]).map((v) => [v, process.env[v]] as const),
|
||||||
|
);
|
||||||
|
const flipperServer = new FlipperServerImpl(
|
||||||
|
{
|
||||||
|
env: envVars,
|
||||||
|
gatekeepers: getGatekeepers(),
|
||||||
|
isProduction,
|
||||||
|
paths: {
|
||||||
|
appPath,
|
||||||
|
homePath: os.homedir(),
|
||||||
|
execPath,
|
||||||
|
staticPath: staticDir,
|
||||||
|
tempPath: os.tmpdir(),
|
||||||
|
desktopPath: desktopPath,
|
||||||
|
},
|
||||||
|
launcherSettings: await loadLauncherSettings(),
|
||||||
|
processConfig: loadProcessConfig(env),
|
||||||
|
settings: await loadSettings(),
|
||||||
|
validWebSocketOrigins: ['localhost:', 'http://localhost:'],
|
||||||
|
},
|
||||||
|
logger,
|
||||||
|
keytar,
|
||||||
|
);
|
||||||
|
|
||||||
|
await flipperServer.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLogger(): Logger {
|
||||||
|
return {
|
||||||
|
track(..._args: [any, any, any?, any?]) {
|
||||||
|
// TODO: only if verbose console.debug(...args);
|
||||||
|
// console.warn('(skipper track)', args);
|
||||||
|
},
|
||||||
|
trackTimeSince(..._args: [any, any, any?]) {
|
||||||
|
// TODO: only if verbose console.debug(...args);
|
||||||
|
// console.warn('(skipped trackTimeSince)', args);
|
||||||
|
},
|
||||||
|
debug(..._args: any[]) {
|
||||||
|
// TODO: only if verbose console.debug(...args);
|
||||||
|
},
|
||||||
|
error(...args: any[]) {
|
||||||
|
console.error(...args);
|
||||||
|
console.warn('(skipped error reporting)');
|
||||||
|
},
|
||||||
|
warn(...args: any[]) {
|
||||||
|
console.warn(...args);
|
||||||
|
console.warn('(skipped error reporting)');
|
||||||
|
},
|
||||||
|
info(...args: any[]) {
|
||||||
|
console.info(...args);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,9 +7,8 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {hostname} from 'os';
|
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import express, {Express} from 'express';
|
import {Express} from 'express';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
@@ -18,15 +17,6 @@ import {getWatchFolders} from 'flipper-pkg-lib';
|
|||||||
import Metro from 'metro';
|
import Metro from 'metro';
|
||||||
import pFilter from 'p-filter';
|
import pFilter from 'p-filter';
|
||||||
|
|
||||||
const PORT = 52342;
|
|
||||||
const rootDir = path.resolve(__dirname, '..', '..');
|
|
||||||
const staticDir = path.join(rootDir, 'static');
|
|
||||||
const babelTransformationsDir = path.resolve(
|
|
||||||
rootDir,
|
|
||||||
'babel-transformer',
|
|
||||||
'src',
|
|
||||||
);
|
|
||||||
|
|
||||||
const uiSourceDirs = [
|
const uiSourceDirs = [
|
||||||
'flipper-ui-browser',
|
'flipper-ui-browser',
|
||||||
'flipper-ui-core',
|
'flipper-ui-core',
|
||||||
@@ -35,79 +25,22 @@ const uiSourceDirs = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// This file is heavily inspired by scripts/start-dev-server.ts!
|
// This file is heavily inspired by scripts/start-dev-server.ts!
|
||||||
export async function startWebServerDev() {
|
export async function startWebServerDev(
|
||||||
checkDevServer();
|
app: Express,
|
||||||
|
server: http.Server,
|
||||||
|
socket: socketio.Server,
|
||||||
|
rootDir: string,
|
||||||
|
) {
|
||||||
// await prepareDefaultPlugins(
|
// await prepareDefaultPlugins(
|
||||||
// process.env.FLIPPER_RELEASE_CHANNEL === 'insiders',
|
// process.env.FLIPPER_RELEASE_CHANNEL === 'insiders',
|
||||||
// );
|
// );
|
||||||
// await ensurePluginFoldersWatchable();
|
// await ensurePluginFoldersWatchable();
|
||||||
const {app, server} = await startAssetServer(PORT);
|
await startMetroServer(app, server, socket, rootDir);
|
||||||
const socket = await addWebsocket(server);
|
|
||||||
await startMetroServer(app, server, socket);
|
|
||||||
// await compileMain();
|
// await compileMain();
|
||||||
// if (dotenv && dotenv.parsed) {
|
// if (dotenv && dotenv.parsed) {
|
||||||
// console.log('✅ Loaded env vars from .env file: ', dotenv.parsed);
|
// console.log('✅ Loaded env vars from .env file: ', dotenv.parsed);
|
||||||
// }
|
// }
|
||||||
// shutdownElectron = launchElectron(port);
|
// shutdownElectron = launchElectron(port);
|
||||||
console.log(
|
|
||||||
`Flipper DEV server started at http://localhost:${PORT}/index.web.dev.html`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function looksLikeDevServer(): boolean {
|
|
||||||
const hn = hostname();
|
|
||||||
if (/^devvm.*\.facebook\.com$/.test(hn)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (hn.endsWith('.od.fbinfra.net')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkDevServer() {
|
|
||||||
if (looksLikeDevServer()) {
|
|
||||||
console.log(
|
|
||||||
chalk.red(
|
|
||||||
`✖ It looks like you're trying to start Flipper on your OnDemand or DevServer, which is not supported. Please run this in a local checkout on your laptop or desktop instead.`,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startAssetServer(
|
|
||||||
port: number,
|
|
||||||
): Promise<{app: Express; server: http.Server}> {
|
|
||||||
const app = express();
|
|
||||||
|
|
||||||
app.use((_req, res, next) => {
|
|
||||||
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
|
|
||||||
res.header('Expires', '-1');
|
|
||||||
res.header('Pragma', 'no-cache');
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/', (_req, res) => {
|
|
||||||
fs.readFile(path.join(staticDir, 'index.web.dev.html'), (_err, content) => {
|
|
||||||
res.end(content);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(express.static(staticDir));
|
|
||||||
|
|
||||||
const server = http.createServer(app);
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
server.listen(port, 'localhost', () => resolve({app, server}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addWebsocket(server: http.Server) {
|
|
||||||
const io = new socketio.Server(server); // 3.1.0 socket.io doesn't have type definitions
|
|
||||||
|
|
||||||
io.on('connection', (client) => {
|
|
||||||
console.log(chalk.green(`Client connected ${client.id}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Refresh the app on changes.
|
// Refresh the app on changes.
|
||||||
// When Fast Refresh enabled, reloads are performed by HMRClient, so don't need to watch manually here.
|
// When Fast Refresh enabled, reloads are performed by HMRClient, so don't need to watch manually here.
|
||||||
@@ -115,14 +48,20 @@ async function addWebsocket(server: http.Server) {
|
|||||||
// await startWatchChanges(io);
|
// await startWatchChanges(io);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return io;
|
console.log('DEV webserver started.');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startMetroServer(
|
async function startMetroServer(
|
||||||
app: Express,
|
app: Express,
|
||||||
server: http.Server,
|
server: http.Server,
|
||||||
socket: socketio.Server,
|
socket: socketio.Server,
|
||||||
|
rootDir: string,
|
||||||
) {
|
) {
|
||||||
|
const babelTransformationsDir = path.resolve(
|
||||||
|
rootDir,
|
||||||
|
'babel-transformer',
|
||||||
|
'src',
|
||||||
|
);
|
||||||
const watchFolders = await dedupeFolders(
|
const watchFolders = await dedupeFolders(
|
||||||
(
|
(
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
"rootDir": "src"
|
"rootDir": "src"
|
||||||
},
|
},
|
||||||
"references": [
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../flipper-common"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "../flipper-server-core"
|
"path": "../flipper-server-core"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user