From 387a55de400c747db049e06e5d8ed7c3d0029062 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Tue, 5 Sep 2017 07:10:42 -0700 Subject: [PATCH] Make the DeltaCalculator and the DeltaTransformer emit change events Reviewed By: jeanlauliac Differential Revision: D5765042 fbshipit-source-id: 5b45cc425b6afb4f8cead80ce967263936baa8c1 --- .../src/DeltaBundler/DeltaCalculator.js | 13 ++++++++--- .../src/DeltaBundler/DeltaTransformer.js | 14 +++++++++++- .../__tests__/DeltaCalculator-test.js | 22 +++++++++++++++++++ .../metro-bundler/src/DeltaBundler/index.js | 19 +++++++++++----- 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/packages/metro-bundler/src/DeltaBundler/DeltaCalculator.js b/packages/metro-bundler/src/DeltaBundler/DeltaCalculator.js index fffee2ec..ce26135c 100644 --- a/packages/metro-bundler/src/DeltaBundler/DeltaCalculator.js +++ b/packages/metro-bundler/src/DeltaBundler/DeltaCalculator.js @@ -12,6 +12,8 @@ 'use strict'; +const {EventEmitter} = require('events'); + import type Bundler, {BundlingOptions} from '../Bundler'; import type {Options as JSTransformerOptions} from '../JSTransformer/worker'; import type Resolver from '../Resolver'; @@ -31,7 +33,7 @@ export type DeltaResult = { * traverse the files that have been changed between calls and avoid having to * traverse the whole dependency tree for trivial small changes. */ -class DeltaCalculator { +class DeltaCalculator extends EventEmitter { _bundler: Bundler; _resolver: Resolver; _options: BundleOptions; @@ -46,6 +48,8 @@ class DeltaCalculator { _inverseDependencies: Map> = new Map(); constructor(bundler: Bundler, resolver: Resolver, options: BundleOptions) { + super(); + this._bundler = bundler; this._options = options; this._resolver = resolver; @@ -166,8 +170,11 @@ class DeltaCalculator { }): mixed => { this._modifiedFiles.add(filePath); - // TODO: Check if path is in current dependencies. If so, send an updated - // bundle event. + // Notify users that there is a change in some of the bundle files. This + // way the client can choose to refetch the bundle. + if (this._dependencies.has(filePath)) { + this.emit('change'); + } }; async _getDelta(modifiedFiles: Set): Promise { diff --git a/packages/metro-bundler/src/DeltaBundler/DeltaTransformer.js b/packages/metro-bundler/src/DeltaBundler/DeltaTransformer.js index d2836de2..fc6c9e5e 100644 --- a/packages/metro-bundler/src/DeltaBundler/DeltaTransformer.js +++ b/packages/metro-bundler/src/DeltaBundler/DeltaTransformer.js @@ -14,6 +14,8 @@ const DeltaCalculator = require('./DeltaCalculator'); +const {EventEmitter} = require('events'); + import type Bundler from '../Bundler'; import type {Options as JSTransformerOptions} from '../JSTransformer/worker'; import type Resolver from '../Resolver'; @@ -49,7 +51,7 @@ type Options = {| * }, * } */ -class DeltaTransformer { +class DeltaTransformer extends EventEmitter { _bundler: Bundler; _getPolyfills: ({platform: ?string}) => $ReadOnlyArray; _polyfillModuleNames: $ReadOnlyArray; @@ -64,12 +66,16 @@ class DeltaTransformer { options: Options, bundleOptions: BundleOptions, ) { + super(); + this._bundler = bundler; this._deltaCalculator = deltaCalculator; this._getPolyfills = options.getPolyfills; this._polyfillModuleNames = options.polyfillModuleNames; this._getModuleId = this._bundler.getGetModuleIdFn(); this._bundleOptions = bundleOptions; + + this._deltaCalculator.on('change', this._onFileChange); } static async create( @@ -95,6 +101,8 @@ class DeltaTransformer { * clean up memory and resources once this instance is not used anymore. */ end() { + this._deltaCalculator.removeListener('change', this._onFileChange); + return this._deltaCalculator.end(); } @@ -348,6 +356,10 @@ class DeltaTransformer { return await module.read(transformOptions); } + + _onFileChange = () => { + this.emit('change'); + }; } module.exports = DeltaTransformer; diff --git a/packages/metro-bundler/src/DeltaBundler/__tests__/DeltaCalculator-test.js b/packages/metro-bundler/src/DeltaBundler/__tests__/DeltaCalculator-test.js index f9e1f6e0..0fa14749 100644 --- a/packages/metro-bundler/src/DeltaBundler/__tests__/DeltaCalculator-test.js +++ b/packages/metro-bundler/src/DeltaBundler/__tests__/DeltaCalculator-test.js @@ -187,4 +187,26 @@ describe('DeltaCalculator', () => { deleted: new Set(['/bar', '/baz']), }); }); + + it('should emit an event when there is a relevant file change', async done => { + await deltaCalculator.getDelta(); + + deltaCalculator.on('change', () => done()); + + fileWatcher.emit('change', {eventsQueue: [{filePath: '/foo'}]}); + }); + + it('should not emit an event when there is a file changed outside the bundle', async () => { + jest.useFakeTimers(); + + const onChangeFile = jest.fn(); + await deltaCalculator.getDelta(); + + deltaCalculator.on('change', onChangeFile); + fileWatcher.emit('change', {eventsQueue: [{filePath: '/another'}]}); + + jest.runAllTimers(); + + expect(onChangeFile.mock.calls.length).toBe(0); + }); }); diff --git a/packages/metro-bundler/src/DeltaBundler/index.js b/packages/metro-bundler/src/DeltaBundler/index.js index 21c06552..762d9a43 100644 --- a/packages/metro-bundler/src/DeltaBundler/index.js +++ b/packages/metro-bundler/src/DeltaBundler/index.js @@ -58,10 +58,19 @@ class DeltaBundler { this._options = options; } - /** - * Main method to build a Delta Bundler - */ async build(options: Options): Promise { + const {deltaTransformer, id} = await this.getDeltaTransformer(options); + const response = await deltaTransformer.getDelta(); + + return { + ...response, + id, + }; + } + + async getDeltaTransformer( + options: Options, + ): Promise<{deltaTransformer: DeltaTransformer, id: string}> { let bundleId = options.deltaBundleId; // If no bundle id is passed, generate a new one (which is going to be @@ -83,10 +92,8 @@ class DeltaBundler { this._deltaTransformers.set(bundleId, deltaTransformer); } - const response = await deltaTransformer.getDelta(); - return { - ...response, + deltaTransformer, id: bundleId, }; }