diff --git a/packages/metro-bundler/src/Server/index.js b/packages/metro-bundler/src/Server/index.js index bff8d49b..5b1bf2ad 100644 --- a/packages/metro-bundler/src/Server/index.js +++ b/packages/metro-bundler/src/Server/index.js @@ -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 { diff --git a/packages/metro-bundler/src/lib/terminal.js b/packages/metro-bundler/src/lib/TerminalClass.js similarity index 88% rename from packages/metro-bundler/src/lib/terminal.js rename to packages/metro-bundler/src/lib/TerminalClass.js index 04043db5..7f767fb9 100644 --- a/packages/metro-bundler/src/lib/terminal.js +++ b/packages/metro-bundler/src/lib/TerminalClass.js @@ -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; _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; - - 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; diff --git a/packages/metro-bundler/src/lib/TerminalReporter.js b/packages/metro-bundler/src/lib/TerminalReporter.js index 58594364..aa4ef26c 100644 --- a/packages/metro-bundler/src/lib/TerminalReporter.js +++ b/packages/metro-bundler/src/lib/TerminalReporter.js @@ -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) { - 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 '), '\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 '), '\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()); } } diff --git a/packages/metro-bundler/src/lib/TransformCaching.js b/packages/metro-bundler/src/lib/TransformCaching.js index fe633107..dfbc0b89 100644 --- a/packages/metro-bundler/src/lib/TransformCaching.js +++ b/packages/metro-bundler/src/lib/TransformCaching.js @@ -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(); } diff --git a/packages/metro-bundler/src/lib/__tests__/terminal-test.js b/packages/metro-bundler/src/lib/__tests__/TerminalClass-test.js similarity index 95% rename from packages/metro-bundler/src/lib/__tests__/terminal-test.js rename to packages/metro-bundler/src/lib/__tests__/TerminalClass-test.js index 612c028d..9c8470f9 100644 --- a/packages/metro-bundler/src/lib/__tests__/terminal-test.js +++ b/packages/metro-bundler/src/lib/__tests__/TerminalClass-test.js @@ -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( diff --git a/packages/metro-bundler/src/lib/__tests__/TransformCaching-test.js b/packages/metro-bundler/src/lib/__tests__/TransformCaching-test.js index d1604e85..107503d1 100644 --- a/packages/metro-bundler/src/lib/__tests__/TransformCaching-test.js +++ b/packages/metro-bundler/src/lib/__tests__/TransformCaching-test.js @@ -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']); diff --git a/packages/metro-bundler/src/lib/reporting.js b/packages/metro-bundler/src/lib/reporting.js index 899bc9f7..e4e7c482 100644 --- a/packages/metro-bundler/src/lib/reporting.js +++ b/packages/metro-bundler/src/lib/reporting.js @@ -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';