metro-bundler: Terminal: remove global state
Reviewed By: cpojer Differential Revision: D5155075 fbshipit-source-id: 1d64bdd0ae13087aca620b65892832e3a1229c4a
This commit is contained in:
parent
1f3140c496
commit
365c1bfcf9
|
@ -13,6 +13,7 @@
|
|||
|
||||
const log = require('../util/log').out('bundle');
|
||||
const Server = require('../../packager/src/Server');
|
||||
const Terminal = require('../../packager/src/lib/TerminalClass');
|
||||
const TerminalReporter = require('../../packager/src/lib/TerminalReporter');
|
||||
const TransformCaching = require('../../packager/src/lib/TransformCaching');
|
||||
|
||||
|
@ -74,9 +75,13 @@ function buildBundle(
|
|||
: config.getTransformModulePath();
|
||||
|
||||
const providesModuleNodeModules =
|
||||
typeof config.getProvidesModuleNodeModules === 'function' ? config.getProvidesModuleNodeModules() :
|
||||
defaultProvidesModuleNodeModules;
|
||||
typeof config.getProvidesModuleNodeModules === 'function'
|
||||
? config.getProvidesModuleNodeModules()
|
||||
: defaultProvidesModuleNodeModules;
|
||||
|
||||
/* $FlowFixMe: Flow is wrong, Node.js docs specify that process.stdout is an
|
||||
* instance of a net.Socket (a local socket, not network). */
|
||||
const terminal = new Terminal(process.stdout);
|
||||
const options = {
|
||||
assetExts: defaultAssetExts.concat(assetExts),
|
||||
blacklistRE: config.getBlacklistRE(),
|
||||
|
@ -90,7 +95,7 @@ function buildBundle(
|
|||
projectRoots: config.getProjectRoots(),
|
||||
providesModuleNodeModules: providesModuleNodeModules,
|
||||
resetCache: args.resetCache,
|
||||
reporter: new TerminalReporter(),
|
||||
reporter: new TerminalReporter(terminal),
|
||||
sourceExts: defaultSourceExts.concat(sourceExts),
|
||||
transformCache: TransformCaching.useTempDir(),
|
||||
transformModulePath: transformModulePath,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
require('../../setupBabel')();
|
||||
const InspectorProxy = require('./util/inspectorProxy.js');
|
||||
const ReactPackager = require('../../packager');
|
||||
const Terminal = require('../../packager/src/lib/TerminalClass');
|
||||
|
||||
const attachHMRServer = require('./util/attachHMRServer');
|
||||
const connect = require('connect');
|
||||
|
@ -138,6 +139,9 @@ function getPackagerServer(args, config) {
|
|||
LogReporter = require('../../packager/src/lib/TerminalReporter');
|
||||
}
|
||||
|
||||
/* $FlowFixMe: Flow is wrong, Node.js docs specify that process.stdout is an
|
||||
* instance of a net.Socket (a local socket, not network). */
|
||||
const terminal = new Terminal(process.stdout);
|
||||
return ReactPackager.createServer({
|
||||
assetExts: defaultAssetExts.concat(args.assetExts),
|
||||
blacklistRE: config.getBlacklistRE(),
|
||||
|
@ -151,7 +155,7 @@ function getPackagerServer(args, config) {
|
|||
postMinifyProcess: config.postMinifyProcess,
|
||||
projectRoots: args.projectRoots,
|
||||
providesModuleNodeModules: providesModuleNodeModules,
|
||||
reporter: new LogReporter(),
|
||||
reporter: new LogReporter(terminal),
|
||||
resetCache: args.resetCache,
|
||||
sourceExts: defaultSourceExts.concat(args.sourceExts),
|
||||
transformModulePath: transformModulePath,
|
||||
|
|
|
@ -21,7 +21,6 @@ const mime = require('mime-types');
|
|||
const parsePlatformFilePath = require('../node-haste/lib/parsePlatformFilePath');
|
||||
const path = require('path');
|
||||
const symbolicate = require('./symbolicate');
|
||||
const terminal = require('../lib/terminal');
|
||||
const url = require('url');
|
||||
|
||||
const debug = require('debug')('RNP:Server');
|
||||
|
@ -396,7 +395,8 @@ class Server {
|
|||
e => {
|
||||
res.writeHead(500);
|
||||
res.end('Internal Error');
|
||||
terminal.log(e.stack); // eslint-disable-line no-console-disallow
|
||||
// FIXME: $FlowFixMe: that's a hack, doesn't work with JSON-mode output
|
||||
this._reporter.terminal && this._reporter.terminal.log(e.stack);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -84,7 +85,6 @@ function getTTYStream(stream: net$Socket): ?tty.WriteStream {
|
|||
* single responsibility of handling status messages.
|
||||
*/
|
||||
class Terminal {
|
||||
|
||||
_logLines: Array<string>;
|
||||
_nextStatusStr: string;
|
||||
_scheduleUpdate: () => void;
|
||||
|
@ -120,7 +120,10 @@ class Terminal {
|
|||
});
|
||||
this._logLines = [];
|
||||
if (ttyStream != null) {
|
||||
this._nextStatusStr = chunkString(this._nextStatusStr, ttyStream.columns).join('\n');
|
||||
this._nextStatusStr = chunkString(
|
||||
this._nextStatusStr,
|
||||
ttyStream.columns,
|
||||
).join('\n');
|
||||
_stream.write(this._nextStatusStr);
|
||||
}
|
||||
this._statusStr = this._nextStatusStr;
|
||||
|
@ -158,25 +161,6 @@ class Terminal {
|
|||
this.log(this._nextStatusStr);
|
||||
this._nextStatusStr = '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* On the same pattern as node.js `console` module, we export the stdout-based
|
||||
* terminal at the top-level, but provide access to the Terminal class as a
|
||||
* field (so it can be used, for instance, with stderr).
|
||||
*/
|
||||
class GlobalTerminal extends Terminal {
|
||||
|
||||
Terminal: Class<Terminal>;
|
||||
|
||||
constructor() {
|
||||
/* $FlowFixMe: Flow is wrong, Node.js docs specify that process.stdout is an
|
||||
* instance of a net.Socket (a local socket, not network). */
|
||||
super(process.stdout);
|
||||
this.Terminal = Terminal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = new GlobalTerminal();
|
||||
module.exports = Terminal;
|
|
@ -15,10 +15,10 @@ const chalk = require('chalk');
|
|||
const formatBanner = require('./formatBanner');
|
||||
const path = require('path');
|
||||
const reporting = require('./reporting');
|
||||
const terminal = require('./terminal');
|
||||
const throttle = require('lodash/throttle');
|
||||
const util = require('util');
|
||||
|
||||
import type Terminal from './TerminalClass';
|
||||
import type {ReportableEvent, GlobalCacheDisabledReason} from './reporting';
|
||||
|
||||
const DEP_GRAPH_MESSAGE = 'Loading dependency graph';
|
||||
|
@ -72,12 +72,15 @@ class TerminalReporter {
|
|||
totalFileCount: number,
|
||||
}) => void;
|
||||
|
||||
constructor() {
|
||||
+terminal: Terminal;
|
||||
|
||||
constructor(terminal: Terminal) {
|
||||
this._dependencyGraphHasLoaded = false;
|
||||
this._activeBundles = new Map();
|
||||
this._scheduleUpdateBundleProgress = throttle(data => {
|
||||
this.update({...data, type: 'bundle_transform_progressed_throttled'});
|
||||
}, 100);
|
||||
(this: any).terminal = terminal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,10 +109,18 @@ class TerminalReporter {
|
|||
const format = GLOBAL_CACHE_DISABLED_MESSAGE_FORMAT;
|
||||
switch (reason) {
|
||||
case 'too_many_errors':
|
||||
reporting.logWarning(terminal, format, 'it has been failing too many times.');
|
||||
reporting.logWarning(
|
||||
this.terminal,
|
||||
format,
|
||||
'it has been failing too many times.',
|
||||
);
|
||||
break;
|
||||
case 'too_many_misses':
|
||||
reporting.logWarning(terminal, format, 'it has been missing too many consecutive keys.');
|
||||
reporting.logWarning(
|
||||
this.terminal,
|
||||
format,
|
||||
'it has been missing too many consecutive keys.',
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +133,7 @@ class TerminalReporter {
|
|||
ratio: 1,
|
||||
transformedFileCount: progress.totalFileCount,
|
||||
}, 'done');
|
||||
terminal.log(msg);
|
||||
this.terminal.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,12 +141,12 @@ class TerminalReporter {
|
|||
const progress = this._activeBundles.get(buildID);
|
||||
if (progress != null) {
|
||||
const msg = this._getBundleStatusMessage(progress, 'failed');
|
||||
terminal.log(msg);
|
||||
this.terminal.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
_logPackagerInitializing(port: number, projectRoots: $ReadOnlyArray<string>) {
|
||||
terminal.log(
|
||||
this.terminal.log(
|
||||
formatBanner(
|
||||
'Running packager on port ' +
|
||||
port +
|
||||
|
@ -152,7 +163,7 @@ class TerminalReporter {
|
|||
)
|
||||
);
|
||||
|
||||
terminal.log(
|
||||
this.terminal.log(
|
||||
'Looking for JS files in\n ',
|
||||
chalk.dim(projectRoots.join('\n ')),
|
||||
'\n'
|
||||
|
@ -161,23 +172,23 @@ class TerminalReporter {
|
|||
|
||||
_logPackagerInitializingFailed(port: number, error: Error) {
|
||||
if (error.code === 'EADDRINUSE') {
|
||||
terminal.log(
|
||||
this.terminal.log(
|
||||
chalk.bgRed.bold(' ERROR '),
|
||||
chalk.red("Packager can't listen on port", chalk.bold(port))
|
||||
);
|
||||
terminal.log('Most likely another process is already using this port');
|
||||
terminal.log('Run the following command to find out which process:');
|
||||
terminal.log('\n ', chalk.bold('lsof -i :' + port), '\n');
|
||||
terminal.log('Then, you can either shut down the other process:');
|
||||
terminal.log('\n ', chalk.bold('kill -9 <PID>'), '\n');
|
||||
terminal.log('or run packager on different port.');
|
||||
this.terminal.log('Most likely another process is already using this port');
|
||||
this.terminal.log('Run the following command to find out which process:');
|
||||
this.terminal.log('\n ', chalk.bold('lsof -i :' + port), '\n');
|
||||
this.terminal.log('Then, you can either shut down the other process:');
|
||||
this.terminal.log('\n ', chalk.bold('kill -9 <PID>'), '\n');
|
||||
this.terminal.log('or run packager on different port.');
|
||||
} else {
|
||||
terminal.log(chalk.bgRed.bold(' ERROR '), chalk.red(error.message));
|
||||
this.terminal.log(chalk.bgRed.bold(' ERROR '), chalk.red(error.message));
|
||||
const errorAttributes = JSON.stringify(error);
|
||||
if (errorAttributes !== '{}') {
|
||||
terminal.log(chalk.red(errorAttributes));
|
||||
this.terminal.log(chalk.red(errorAttributes));
|
||||
}
|
||||
terminal.log(chalk.red(error.stack));
|
||||
this.terminal.log(chalk.red(error.stack));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +202,7 @@ class TerminalReporter {
|
|||
this._logPackagerInitializing(event.port, event.projectRoots);
|
||||
break;
|
||||
case 'initialize_packager_done':
|
||||
terminal.log('\nReact packager ready.\n');
|
||||
this.terminal.log('\nReact packager ready.\n');
|
||||
break;
|
||||
case 'initialize_packager_failed':
|
||||
this._logPackagerInitializingFailed(event.port, event.error);
|
||||
|
@ -206,13 +217,13 @@ class TerminalReporter {
|
|||
this._logBundlingError(event.error);
|
||||
break;
|
||||
case 'dep_graph_loaded':
|
||||
terminal.log(`${DEP_GRAPH_MESSAGE}, done.`);
|
||||
this.terminal.log(`${DEP_GRAPH_MESSAGE}, done.`);
|
||||
break;
|
||||
case 'global_cache_disabled':
|
||||
this._logCacheDisabled(event.reason);
|
||||
break;
|
||||
case 'transform_cache_reset':
|
||||
reporting.logWarning(terminal, 'the transform cache was reset.');
|
||||
reporting.logWarning(this.terminal, 'the transform cache was reset.');
|
||||
break;
|
||||
case 'worker_stdout_chunk':
|
||||
this._logWorkerChunk('stdout', event.chunk);
|
||||
|
@ -230,7 +241,7 @@ class TerminalReporter {
|
|||
*/
|
||||
_logBundlingError(error: Error) {
|
||||
const str = JSON.stringify(error.message);
|
||||
reporting.logError(terminal, 'bundling failed: %s', str);
|
||||
reporting.logError(this.terminal, 'bundling failed: %s', str);
|
||||
}
|
||||
|
||||
_logWorkerChunk(origin: 'stdout' | 'stderr', chunk: string) {
|
||||
|
@ -239,7 +250,7 @@ class TerminalReporter {
|
|||
lines.splice(lines.length - 1, 1);
|
||||
}
|
||||
lines.forEach(line => {
|
||||
terminal.log(`transform[${origin}]: ${line}`);
|
||||
this.terminal.log(`transform[${origin}]: ${line}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -335,7 +346,7 @@ class TerminalReporter {
|
|||
update(event: TerminalReportableEvent) {
|
||||
this._log(event);
|
||||
this._updateState(event);
|
||||
terminal.status(this._getStatusMessage());
|
||||
this.terminal.status(this._getStatusMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ const invariant = require('fbjs/lib/invariant');
|
|||
const mkdirp = require('mkdirp');
|
||||
const path = require('path');
|
||||
const rimraf = require('rimraf');
|
||||
const terminal = require('../lib/terminal');
|
||||
const writeFileAtomicSync = require('write-file-atomic').sync;
|
||||
|
||||
import type {Options as WorkerOptions} from '../JSTransformer/worker';
|
||||
|
@ -226,7 +225,7 @@ class FileBasedCache {
|
|||
lastCollected == null ||
|
||||
Date.now() - lastCollected > GARBAGE_COLLECTION_PERIOD
|
||||
) {
|
||||
this._collectSyncNoThrow();
|
||||
this._collectSyncNoThrow(options.reporter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,15 +240,19 @@ class FileBasedCache {
|
|||
* We want to avoid preventing tool use if the cleanup fails for some reason,
|
||||
* but still provide some chance for people to report/fix things.
|
||||
*/
|
||||
_collectSyncNoThrow() {
|
||||
_collectSyncNoThrow(reporter: Reporter) {
|
||||
try {
|
||||
this._collectCacheIfOldSync();
|
||||
} catch (error) {
|
||||
terminal.log(error.stack);
|
||||
terminal.log(
|
||||
'Error: Cleaning up the cache folder failed. Continuing anyway.',
|
||||
);
|
||||
terminal.log('The cache folder is: %s', this._rootPath);
|
||||
// FIXME: $FlowFixMe: this is a hack, only works for TerminalReporter
|
||||
const {terminal} = reporter;
|
||||
if (terminal != null) {
|
||||
terminal.log(error.stack);
|
||||
terminal.log(
|
||||
'Error: Cleaning up the cache folder failed. Continuing anyway.',
|
||||
);
|
||||
terminal.log('The cache folder is: %s', this._rootPath);
|
||||
}
|
||||
}
|
||||
this._lastCollected = Date.now();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
jest.dontMock('../terminal').dontMock('lodash/throttle');
|
||||
jest.dontMock('../TerminalClass').dontMock('lodash/throttle');
|
||||
|
||||
jest.mock('readline', () => ({
|
||||
moveCursor: (stream, dx, dy) => {
|
||||
|
@ -27,14 +27,14 @@ jest.mock('readline', () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
describe('terminal', () => {
|
||||
describe('Terminal', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
function prepare(isTTY) {
|
||||
const {Terminal} = require('../terminal');
|
||||
const Terminal = require('../TerminalClass');
|
||||
const lines = 10;
|
||||
const columns = 10;
|
||||
const stream = Object.create(
|
|
@ -88,7 +88,7 @@ describe('TransformCaching.FileBasedCache', () => {
|
|||
const {result} = args;
|
||||
const cachedResult = transformCache.readSync({
|
||||
...args,
|
||||
cacheOptions: {resetCache: false},
|
||||
cacheOptions: {reporter: {}, resetCache: false},
|
||||
});
|
||||
expect(cachedResult.result).toEqual(result);
|
||||
});
|
||||
|
@ -121,7 +121,7 @@ describe('TransformCaching.FileBasedCache', () => {
|
|||
const {result} = args;
|
||||
const cachedResult = transformCache.readSync({
|
||||
...args,
|
||||
cacheOptions: {resetCache: false},
|
||||
cacheOptions: {reporter: {}, resetCache: false},
|
||||
});
|
||||
expect(cachedResult.result).toEqual(result);
|
||||
});
|
||||
|
@ -129,7 +129,7 @@ describe('TransformCaching.FileBasedCache', () => {
|
|||
allCases.forEach(entry => {
|
||||
const cachedResult = transformCache.readSync({
|
||||
...argsFor(entry),
|
||||
cacheOptions: {resetCache: false},
|
||||
cacheOptions: {reporter: {}, resetCache: false},
|
||||
});
|
||||
expect(cachedResult.result).toBeNull();
|
||||
expect(cachedResult.outdatedDependencies).toEqual(['foo', 'bar']);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
const chalk = require('chalk');
|
||||
const util = require('util');
|
||||
|
||||
import type {Terminal} from './terminal';
|
||||
import type Terminal from './TerminalClass';
|
||||
|
||||
export type GlobalCacheDisabledReason = 'too_many_errors' | 'too_many_misses';
|
||||
|
||||
|
|
Loading…
Reference in New Issue