Files
flipper/desktop/scripts/start-dev-server.ts
dependabot[bot] ea4b8b8f8a Bump socket.io from 2.3.0 to 3.1.0 in /desktop (#1845)
Summary:
Bumps [socket.io](https://github.com/socketio/socket.io) from 2.3.0 to 3.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/socketio/socket.io/releases">socket.io's releases</a>.</em></p>
<blockquote>
<h2>3.1.0</h2>
<p>In order to ease the migration to Socket.IO v3, the v3 server is now able to communicate with v2 clients:</p>
<pre lang="js"><code>const io = require(&quot;socket.io&quot;)({
  allowEIO3: true // false by default
});
</code></pre>
<p>Note: the <code>allowEIO3</code> refers to the version 3 of the Engine.IO protocol which is used in Socket.IO v2</p>
<h3>Features</h3>
<ul>
<li>confirm a weak but matching ETag (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3485">#3485</a>) (<a href="161091dd4c">161091d</a>)</li>
<li><strong>esm:</strong> export the Namespace and Socket class (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3699">#3699</a>) (<a href="233650c222">233650c</a>)</li>
<li>add support for Socket.IO v2 clients (<a href="9925746c8e">9925746</a>)</li>
<li>add room events (<a href="155fa6333a">155fa63</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>allow integers as event names (<a href="1c220ddbf4">1c220dd</a>)</li>
</ul>
<h4>Links:</h4>
<ul>
<li>Milestone: -</li>
<li>Diff: <a href="https://github.com/socketio/socket.io/compare/3.0.5...3.1.0">https://github.com/socketio/socket.io/compare/3.0.5...3.1.0</a></li>
<li>Client release: <a href="https://github.com/socketio/socket.io-client/releases/tag/3.1.0">3.1.0</a></li>
<li>engine.io version:  <code>~4.1.0</code></li>
<li>ws version: <code>~7.4.2</code></li>
</ul>
<h2>3.0.5</h2>
<h3>Bug Fixes</h3>
<ul>
<li>properly clear timeout on connection failure (<a href="170b739f14">170b739</a>)</li>
</ul>
<h3>Reverts</h3>
<ul>
<li>restore the socket middleware functionality (<a href="bf54327421">bf54327</a>)</li>
</ul>
<h4>Links:</h4>
<ul>
<li>Milestone: -</li>
<li>Diff: <a href="https://github.com/socketio/socket.io/compare/3.0.4...3.0.5">https://github.com/socketio/socket.io/compare/3.0.4...3.0.5</a></li>
<li>Client release: <a href="https://github.com/socketio/socket.io-client/releases/tag/3.0.5">3.0.5</a></li>
<li>engine.io version:  <code>~4.0.6</code></li>
<li>ws version: <code>~7.4.2</code></li>
</ul>

</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/socketio/socket.io/blob/master/CHANGELOG.md">socket.io's changelog</a>.</em></p>
<blockquote>
<h1><a href="https://github.com/socketio/socket.io/compare/3.0.5...3.1.0">3.1.0</a> (2021-01-15)</h1>
<h3>Features</h3>
<ul>
<li>confirm a weak but matching ETag (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3485">#3485</a>) (<a href="161091dd4c">161091d</a>)</li>
<li><strong>esm:</strong> export the Namespace and Socket class (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3699">#3699</a>) (<a href="233650c222">233650c</a>)</li>
<li>add support for Socket.IO v2 clients (<a href="9925746c8e">9925746</a>)</li>
<li>add room events (<a href="155fa6333a">155fa63</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>allow integers as event names (<a href="1c220ddbf4">1c220dd</a>)</li>
</ul>
<h2><a href="https://github.com/socketio/socket.io/compare/3.0.4...3.0.5">3.0.5</a> (2021-01-05)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>properly clear timeout on connection failure (<a href="170b739f14">170b739</a>)</li>
</ul>
<h3>Reverts</h3>
<ul>
<li>restore the socket middleware functionality (<a href="bf54327421">bf54327</a>)</li>
</ul>
<h2><a href="https://github.com/socketio/socket.io/compare/3.0.3...3.0.4">3.0.4</a> (2020-12-07)</h2>
<h2><a href="https://github.com/socketio/socket.io/compare/3.0.2...3.0.3">3.0.3</a> (2020-11-19)</h2>
<h2><a href="https://github.com/socketio/socket.io/compare/3.0.1...3.0.2">3.0.2</a> (2020-11-17)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>merge Engine.IO options (<a href="43705d7a91">43705d7</a>)</li>
</ul>
<h2><a href="https://github.com/socketio/socket.io/compare/3.0.0...3.0.1">3.0.1</a> (2020-11-09)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>export ServerOptions and Namespace types (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3684">#3684</a>) (<a href="f62f180eda">f62f180</a>)</li>
<li><strong>typings:</strong> update the signature of the emit method (<a href="50671d984a">50671d9</a>)</li>
</ul>

</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="f05a4a6f82"><code>f05a4a6</code></a> chore(release): 3.1.0</li>
<li><a href="2c883f5d4e"><code>2c883f5</code></a> chore: bump socket.io-adapter version</li>
<li><a href="161091dd4c"><code>161091d</code></a> feat: confirm a weak but matching ETag (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3485">#3485</a>)</li>
<li><a href="d52532b7be"><code>d52532b</code></a> docs: add other client implementations (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3593">#3593</a>)</li>
<li><a href="6b1d7901db"><code>6b1d790</code></a> docs(examples): Improve the chat example with more ES6 features (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3240">#3240</a>)</li>
<li><a href="b55892ae80"><code>b55892a</code></a> docs: add run on repl.it badge to README (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3617">#3617</a>)</li>
<li><a href="233650c222"><code>233650c</code></a> feat(esm): export the Namespace and Socket class (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3699">#3699</a>)</li>
<li><a href="9925746c8e"><code>9925746</code></a> feat: add support for Socket.IO v2 clients</li>
<li><a href="de8dffd252"><code>de8dffd</code></a> refactor: strict type check in if expressions (<a href="https://github-redirect.dependabot.com/socketio/socket.io/issues/3744">#3744</a>)</li>
<li><a href="f8a66fd11a"><code>f8a66fd</code></a> chore(release): 3.0.5</li>
<li>Additional commits viewable in <a href="https://github.com/socketio/socket.io/compare/2.3.0...3.1.0">compare view</a></li>
</ul>
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=socket.io&package-manager=npm_and_yarn&previous-version=2.3.0&new-version=3.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

 ---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `dependabot rebase` will rebase this PR
- `dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `dependabot merge` will merge this PR after your CI passes on it
- `dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `dependabot cancel merge` will cancel a previously requested merge and block automerging
- `dependabot reopen` will reopen this PR if it is closed
- `dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

</details>

Pull Request resolved: https://github.com/facebook/flipper/pull/1845

Reviewed By: mweststrate

Differential Revision: D25945568

Pulled By: priteshrnandgaonkar

fbshipit-source-id: 31e4955729b2ce16de88243e9520429f59922d58
2021-01-19 18:45:38 -08:00

414 lines
13 KiB
TypeScript

/**
* 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
*/
const dotenv = require('dotenv').config();
const electronBinary: string = require('electron') as any;
import codeFrame from '@babel/code-frame';
import socketIo from 'socket.io';
import express, {Express} from 'express';
import detect from 'detect-port';
import child from 'child_process';
import AnsiToHtmlConverter from 'ansi-to-html';
import chalk from 'chalk';
import http from 'http';
import path from 'path';
import fs from 'fs-extra';
import {hostname} from 'os';
import {compileMain, generatePluginEntryPoints} from './build-utils';
import Watchman from './watchman';
import Metro from 'metro';
import MetroResolver from 'metro-resolver';
import {staticDir, appDir, babelTransformationsDir} from './paths';
import isFB from './isFB';
import getAppWatchFolders from './get-app-watch-folders';
import {getPluginSourceFolders} from 'flipper-plugin-lib';
import ensurePluginFoldersWatchable from './ensurePluginFoldersWatchable';
import startWatchPlugins from './startWatchPlugins';
import yargs from 'yargs';
const argv = yargs
.usage('yarn start [args]')
.options({
'embedded-plugins': {
describe:
'Enables embedding of plugins into Flipper bundle. If it disabled then only installed plugins are loaded. The flag is enabled by default. Env var FLIPPER_NO_EMBEDDED_PLUGINS is equivalent to the command-line option "--no-embedded-plugins".',
type: 'boolean',
},
'fast-refresh': {
describe:
'Enable Fast Refresh - quick reload of UI component changes without restarting Flipper. The flag is disabled by default. Env var FLIPPER_FAST_REFRESH is equivalent to the command-line option "--fast-refresh".',
type: 'boolean',
},
'plugin-auto-update': {
describe:
'[FB-internal only] Enable plugin auto-updates. The flag is disabled by default in dev mode. Env var FLIPPER_NO_PLUGIN_AUTO_UPDATE is equivalent to the command-line option "--no-plugin-auto-update"',
type: 'boolean',
},
'plugin-auto-update-interval': {
describe:
'[FB-internal only] Set custom interval in milliseconds for plugin auto-update checks. Env var FLIPPER_PLUGIN_AUTO_UPDATE_POLLING_INTERVAL is equivalent to this command-line option.',
type: 'number',
},
'enabled-plugins': {
describe:
'Load only specified plugins and skip loading rest. This is useful when you are developing only one or few plugins. Plugins to load can be specified as a comma-separated list with either plugin id or name used as identifier, e.g. "--enabled-plugins network,inspector". The flag is not provided by default which means that all plugins loaded.',
type: 'array',
},
'open-dev-tools': {
describe:
'Open Dev Tools window on startup. The flag is disabled by default. Env var FLIPPER_OPEN_DEV_TOOLS is equivalent to the command-line option "--open-dev-tools".',
type: 'boolean',
},
'dev-server-port': {
describe:
'Dev server port. 3000 by default. Env var "PORT=3001" is equivalent to the command-line option "--dev-server-port 3001".',
default: 3000,
type: 'number',
},
'enable-all-gks': {
describe:
'[FB-internal only] Will yield `true` on any GK. Disabled by default. Setting env var FLIPPER_ENABLE_ALL_GKS is equivalent',
type: 'boolean',
},
channel: {
describe:
'[FB-internal only] Release channel. "stable" by default. Setting env var "FLIPPER_RELEASE_CHANNEL" is equivalent.',
choices: ['stable', 'insiders'],
},
'public-build': {
describe:
'[FB-internal only] Will force using public sources only, to be able to iterate quickly on the public version. If sources are checked out from GitHub this is already the default. Setting env var "FLIPPER_FORCE_PUBLIC_BUILD" is equivalent.',
type: 'boolean',
},
})
.version('DEV')
.help()
.parse(process.argv.slice(1));
const ansiToHtmlConverter = new AnsiToHtmlConverter();
const DEFAULT_PORT = (process.env.PORT || 3000) as number;
let shutdownElectron: (() => void) | undefined = undefined;
if (isFB) {
process.env.FLIPPER_FB = 'true';
}
if (argv['embedded-plugins'] === true) {
delete process.env.FLIPPER_NO_EMBEDDED_PLUGINS;
} else if (argv['embedded-plugins'] === false) {
process.env.FLIPPER_NO_EMBEDDED_PLUGINS = 'true';
}
if (argv['fast-refresh'] === true) {
process.env.FLIPPER_FAST_REFRESH = 'true';
} else if (argv['fast-refresh'] === false) {
delete process.env.FLIPPER_FAST_REFRESH;
}
if (argv['public-build'] === true) {
// we use a separate env var for forced_public builds, since
// FB_FLIPPER / isFB reflects whether we are running on FB sources / infra
// so changing that will not give the desired result (e.g. incorrect resolve paths, yarn installs)
// this variable purely overrides whether imports are from `fb` or `fb-stubs`
console.log('🐬 Emulating open source build of Flipper');
process.env.FLIPPER_FORCE_PUBLIC_BUILD = 'true';
} else if (argv['public-build'] === false) {
delete process.env.FLIPPER_FORCE_PUBLIC_BUILD;
}
// By default plugin auto-update is disabled in dev mode,
// but it is possible to enable it using this command line
// argument or env var.
if (
argv['plugin-auto-update'] === true ||
process.env.FLIPPER_PLUGIN_AUTO_UPDATE
) {
delete process.env.FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE;
} else {
process.env.FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE = 'true';
}
if (argv['plugin-auto-update-interval']) {
process.env.FLIPPER_PLUGIN_AUTO_UPDATE_POLLING_INTERVAL = `${argv['plugin-auto-update-interval']}`;
}
// Force participating in all GKs. Mostly intersting for Flipper team members.
if (argv['enable-all-gks'] === true) {
process.env.FLIPPER_ENABLE_ALL_GKS = 'true';
}
if (argv['enabled-plugins'] !== undefined) {
process.env.FLIPPER_ENABLED_PLUGINS = argv['enabled-plugins'].join(',');
}
if (argv.channel !== undefined) {
process.env.FLIPPER_RELEASE_CHANNEL = argv.channel;
}
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 launchElectron(port: number) {
const entry = process.env.FLIPPER_FAST_REFRESH ? 'init-fast-refresh' : 'init';
const devServerURL = `http://localhost:${port}`;
const bundleURL = `http://localhost:${port}/src/${entry}.bundle?platform=web&dev=true&minify=false`;
const electronURL = `http://localhost:${port}/index.dev.html`;
const args = [
path.join(staticDir, 'index.js'),
'--remote-debugging-port=9222',
...process.argv,
];
const proc = child.spawn(electronBinary, args, {
cwd: staticDir,
env: {
...process.env,
SONAR_ROOT: process.cwd(),
BUNDLE_URL: bundleURL,
ELECTRON_URL: electronURL,
DEV_SERVER_URL: devServerURL,
},
stdio: 'inherit',
});
const electronCloseListener = () => {
process.exit();
};
const processExitListener = () => {
proc.kill();
};
proc.on('close', electronCloseListener);
process.on('exit', processExitListener);
return () => {
proc.off('close', electronCloseListener);
process.off('exit', processExitListener);
proc.kill();
};
}
async function startMetroServer(app: Express, server: http.Server) {
const watchFolders = (await getAppWatchFolders()).concat(
await getPluginSourceFolders(),
);
const baseConfig = await Metro.loadConfig();
const config = Object.assign({}, baseConfig, {
projectRoot: appDir,
watchFolders,
transformer: {
...baseConfig.transformer,
babelTransformerPath: path.join(babelTransformationsDir, 'transform-app'),
},
resolver: {
...baseConfig.resolver,
resolverMainFields: ['flipperBundlerEntry', 'module', 'main'],
blacklistRE: /\.native\.js$/,
resolveRequest: (context: any, moduleName: string, platform: string) => {
if (moduleName.startsWith('./localhost:3000')) {
moduleName = moduleName.replace('./localhost:3000', '.');
}
return MetroResolver.resolve(
{...context, resolveRequest: null},
moduleName,
platform,
);
},
sourceExts: ['js', 'jsx', 'ts', 'tsx', 'json', 'mjs', 'cjs'],
},
watch: true,
cacheVersion: process.env.FLIPPER_FORCE_PUBLIC_BUILD,
});
const connectMiddleware = await Metro.createConnectMiddleware(config);
app.use(connectMiddleware.middleware);
connectMiddleware.attachHmrServer(server);
}
function startAssetServer(
port: number,
): Promise<{app: Express; server: http.Server}> {
const app = express();
app.use((req, _res, next) => {
if (knownErrors[req.url] != null) {
delete knownErrors[req.url];
outputScreen();
}
next();
});
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.post('/_restartElectron', (_req, res) => {
if (shutdownElectron) {
shutdownElectron();
}
shutdownElectron = launchElectron(port);
res.end();
});
app.get('/', (_req, res) => {
fs.readFile(path.join(staticDir, 'index.dev.html'), (_err, content) => {
res.end(content);
});
});
app.use(express.static(staticDir));
app.use(function (err: any, req: any, res: any, _next: any) {
knownErrors[req.url] = err;
outputScreen();
res.status(500).send('Something broke, check the console!');
});
const server = http.createServer(app);
return new Promise((resolve) => {
server.listen(port, 'localhost', () => resolve({app, server}));
});
}
async function addWebsocket(server: http.Server) {
const io = require('socket.io')(server); // 3.1.0 socket.io doesn't have type definitions
// notify connected clients that there's errors in the console
io.on('connection', (client: any) => {
if (hasErrors()) {
client.emit('hasErrors', ansiToHtmlConverter.toHtml(buildErrorScreen()));
}
});
// Refresh the app on changes.
// When Fast Refresh enabled, reloads are performed by HMRClient, so don't need to watch manually here.
if (!process.env.FLIPPER_FAST_REFRESH) {
await startWatchChanges(io);
}
return io;
}
async function startWatchChanges(io: socketIo.Server) {
try {
const watchman = new Watchman(path.resolve(__dirname, '..'));
await watchman.initialize();
await Promise.all(
['app', 'pkg', 'doctor', 'plugin-lib', 'flipper-plugin'].map((dir) =>
watchman.startWatchFiles(
dir,
() => {
io.emit('refresh');
},
{
excludes: ['**/__tests__/**/*', '**/node_modules/**/*', '**/.*'],
},
),
),
);
await startWatchPlugins(() => {
io.emit('refresh');
});
} catch (err) {
console.error(
'Failed to start watching for changes using Watchman, continue without hot reloading',
err,
);
}
}
const knownErrors: {[key: string]: any} = {};
function hasErrors() {
return Object.keys(knownErrors).length > 0;
}
function buildErrorScreen() {
const lines = [
chalk.red(`✖ Found ${Object.keys(knownErrors).length} errors`),
'',
];
for (const url in knownErrors) {
const err = knownErrors[url];
if (err.filename != null && err.lineNumber != null && err.column != null) {
lines.push(chalk.inverse(err.filename));
lines.push();
lines.push(err.message);
lines.push(
codeFrame(
fs.readFileSync(err.filename, 'utf8'),
err.lineNumber,
err.column,
),
);
} else {
lines.push(err.stack);
}
lines.push('');
}
return lines.join('\n');
}
function outputScreen(socket?: socketIo.Server) {
// output screen
if (hasErrors()) {
const errorScreen = buildErrorScreen();
console.error(errorScreen);
// notify live clients of errors
socket?.emit('hasErrors', ansiToHtmlConverter.toHtml(errorScreen));
} else {
// eslint-disable-next-line no-console
console.log(chalk.green('✔ No known errors'));
}
}
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.`,
),
);
}
}
(async () => {
checkDevServer();
await generatePluginEntryPoints(argv.channel === 'insiders');
await ensurePluginFoldersWatchable();
const port = await detect(DEFAULT_PORT);
const {app, server} = await startAssetServer(port);
const socket = await addWebsocket(server);
await startMetroServer(app, server);
outputScreen(socket);
await compileMain();
if (dotenv && dotenv.parsed) {
console.log('✅ Loaded env vars from .env file: ', dotenv.parsed);
}
shutdownElectron = launchElectron(port);
})();