Skip to content

Commit

Permalink
Add watch option to Server and disable file watchers for runBuild (#507)
Browse files Browse the repository at this point in the history
Summary:
**Summary**

In this PR I am disabling file watching for bundle generation done through `runBuild`. A `watch` option is also added to `Server` in order to enable that (and also because `Server` is used by the React Native CLI instead of `runBuild`).

The goal of this is to solve `ENOSPC` errors related to excessive file watcher use, particularly in CI environments. See: #355

Context:
I previously attempted to fix this by resolving a regression in the existing `watch` config option: #491
Which was closed in favor of a similar PR:  #497
Which was then re-created in: #503 (and landed)

The above PR was modified to automatically set the `watch` value depending on whether it was built in a CI environment. There was a desire to remove the `watch` config option altogether.

At the end, we concluded that there is still a need for a caller to turn off file watching explicitly, and not only through CI detection.

Therefore, I'm threading it through the code as an option that is passed through programmatically and *not* through the config.

Once/if this lands, I will update the React Native CLI to use this option.

**Test plan**

I used the rn-cli as a test harness of sorts.

Invoked metro via `react-native start`
- Observed that the `watch` flag was true through `console.log`

Invoked metro via `react-native bundle`
- Observed that `watch` was set to false.

Relatively new to this project, so please let me know if I should be taking a look at anything else.
Pull Request resolved: #507

Differential Revision: D19341662

Pulled By: cpojer

fbshipit-source-id: d0430364d57fefe027f6b1f58f964d9765cda752
  • Loading branch information
Cristian Sanchez authored and facebook-github-bot committed Jan 10, 2020
1 parent 6ee6285 commit 1a38e00
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 13 deletions.
8 changes: 6 additions & 2 deletions packages/metro/src/Bundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ import type {TransformOptions} from './DeltaBundler/Worker';
import type {TransformResultWithSource} from './DeltaBundler';
import type {ConfigT} from 'metro-config/src/configTypes.flow';

export type BundlerOptions = $ReadOnly<{|
watch?: boolean,
|}>;

class Bundler {
_depGraphPromise: Promise<DependencyGraph>;
_transformer: Transformer;

constructor(config: ConfigT) {
this._depGraphPromise = DependencyGraph.load(config);
constructor(config: ConfigT, options?: BundlerOptions) {
this._depGraphPromise = DependencyGraph.load(config, options);

this._depGraphPromise
.then((dependencyGraph: DependencyGraph) => {
Expand Down
8 changes: 6 additions & 2 deletions packages/metro/src/IncrementalBundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export type GraphRevision = {|
+prepend: $ReadOnlyArray<Module<>>,
|};

export type IncrementalBundlerOptions = $ReadOnly<{|
watch?: boolean,
|}>;

function createRevisionId(): RevisionId {
return crypto.randomBytes(8).toString('hex');
}
Expand All @@ -64,9 +68,9 @@ class IncrementalBundler {
str: string,
) => RevisionId = revisionIdFromString;

constructor(config: ConfigT) {
constructor(config: ConfigT, options?: IncrementalBundlerOptions) {
this._config = config;
this._bundler = new Bundler(config);
this._bundler = new Bundler(config, options);
this._deltaBundler = new DeltaBundler(this._bundler);
}

Expand Down
10 changes: 8 additions & 2 deletions packages/metro/src/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ type ProcessEndContext<T> = {|
+result: T,
|};

export type ServerOptions = $ReadOnly<{|
watch?: boolean,
|}>;

const DELTA_ID_HEADER = 'X-Metro-Delta-ID';
const FILES_CHANGED_COUNT_HEADER = 'X-Metro-Files-Changed-Count';

Expand All @@ -104,7 +108,7 @@ class Server {
_bundler: IncrementalBundler;
_isEnded: boolean;

constructor(config: ConfigT) {
constructor(config: ConfigT, options?: ServerOptions) {
this._config = config;

if (this._config.resetCache) {
Expand All @@ -124,7 +128,9 @@ class Server {
// the HmrServer.
// The whole bundling/serializing logic should follow as well.
this._createModuleId = config.serializer.createModuleIdFactory();
this._bundler = new IncrementalBundler(config);
this._bundler = new IncrementalBundler(config, {
watch: options ? options.watch : undefined,
});
this._nextBundleBuildID = 1;
}

Expand Down
12 changes: 9 additions & 3 deletions packages/metro/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const outputBundle = require('./shared/output/bundle');
const {loadConfig, mergeConfig, getDefaultConfig} = require('metro-config');
const {InspectorProxy} = require('metro-inspector-proxy');

import type {ServerOptions} from './Server';
import type {Graph} from './DeltaBundler';
import type {CustomTransformOptions} from './JSTransformer/worker';
import type {RequestOptions, OutputOptions} from './shared/types.flow.js';
Expand Down Expand Up @@ -107,7 +108,10 @@ async function getConfig(config: InputConfigT): Promise<ConfigT> {
return mergeConfig(defaultConfig, config);
}

async function runMetro(config: InputConfigT): Promise<MetroServer> {
async function runMetro(
config: InputConfigT,
options?: ServerOptions,
): Promise<MetroServer> {
const mergedConfig = await getConfig(config);

mergedConfig.reporter.update({
Expand All @@ -118,7 +122,7 @@ async function runMetro(config: InputConfigT): Promise<MetroServer> {
projectRoots: mergedConfig.watchFolders,
});

return new MetroServer(mergedConfig);
return new MetroServer(mergedConfig, options);
}

exports.runMetro = runMetro;
Expand Down Expand Up @@ -272,7 +276,9 @@ exports.runBuild = async (
map: string,
...
}> => {
const metroServer = await runMetro(config);
const metroServer = await runMetro(config, {
watch: false,
});

try {
const requestOptions: RequestOptions = {
Expand Down
14 changes: 10 additions & 4 deletions packages/metro/src/node-haste/DependencyGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class DependencyGraph extends EventEmitter {
this._createModuleResolver();
}

static _createHaste(config: ConfigT): JestHasteMap {
static _createHaste(config: ConfigT, watch?: boolean): JestHasteMap {
return new JestHasteMap({
cacheDirectory: config.hasteMapCacheDirectory,
computeDependencies: false,
Expand All @@ -93,17 +93,23 @@ class DependencyGraph extends EventEmitter {
roots: config.watchFolders,
throwOnModuleCollision: true,
useWatchman: config.resolver.useWatchman,
watch: !ci.isCI,
watch: watch == null ? !ci.isCI : watch,
});
}

static async load(config: ConfigT): Promise<DependencyGraph> {
static async load(
config: ConfigT,
options?: {|+watch?: boolean|},
): Promise<DependencyGraph> {
const initializingMetroLogEntry = log(
createActionStartEntry('Initializing Metro'),
);

config.reporter.update({type: 'dep_graph_loading'});
const haste = DependencyGraph._createHaste(config);
const haste = DependencyGraph._createHaste(
config,
options && options.watch,
);
const {hasteFS, moduleMap} = await haste.build();

log(createActionEndEntry(initializingMetroLogEntry));
Expand Down

0 comments on commit 1a38e00

Please sign in to comment.