Permalink
Browse files

DeltaPatcher: better support for the new Delta format

Summary: Adds support for the `deleted` key to remove modules from the bundle. Without this, source maps would break after removing a module, since it would still end up in the patched bundle but not in the source map.

Reviewed By: mjesun

Differential Revision: D12874011

fbshipit-source-id: 79239756854cb2c02f14ec8b0bb2b649766393fe
  • Loading branch information...
alexkirsz authored and facebook-github-bot committed Nov 12, 2018
1 parent 0436bfc commit bea57d871f6b5bed76d1625b3e3f483695bd13e9
@@ -63,24 +63,33 @@

// Reset the current bundle when we receive a base bundle.
if (bundle.base) {
this._lastNumModifiedFiles = bundle.modules.length;

this._lastBundle = {
revisionId: undefined,
revisionId: bundle.revisionId,
pre: bundle.pre,
post: bundle.post,
modules: new Map(),
modules: new Map(bundle.modules),
};
}
} else {
this._lastNumModifiedFiles =
bundle.modules.length + bundle.deleted.length;

this._lastNumModifiedFiles = bundle.modules.size;
this._lastBundle.revisionId = bundle.revisionId;

for (const [key, value] of bundle.modules) {
this._lastBundle.modules.set(key, value);
}

for (const id of bundle.deleted) {
this._lastBundle.modules.delete(id);
}
}

if (this._lastNumModifiedFiles > 0) {
this._lastModifiedDate = new Date();
}

this._patchMap(this._lastBundle.modules, bundle.modules);

this._lastBundle.revisionId = bundle.revisionId;

return this;
}

@@ -104,21 +113,11 @@

getAllModules() {
return [].concat(
this._lastBundle.pre,
[this._lastBundle.pre],
Array.from(this._lastBundle.modules.values()),
this._lastBundle.post,
[this._lastBundle.post],
);
}

_patchMap(original, patch) {
for (const [key, value] of patch.entries()) {
if (value == null) {
original.delete(key);
} else {
original.set(key, value);
}
}
}
}

DeltaPatcher._deltaPatchers = new Map();
@@ -0,0 +1,111 @@
/**
* 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
* @emails oncall+javascript_foundation
*/

'use strict';

describe('DeltaPatcher', () => {
const window = (global.window = {});
require('../DeltaPatcher');

it('should initialize to an empty bundle', () => {
global.Date = jest.fn();
const dp = new window.DeltaPatcher();
expect(dp.getLastRevisionId()).toBe(undefined);
expect(dp.getLastModifiedDate()).toBe(global.Date.mock.instances[0]);
expect(dp.getLastNumModifiedFiles()).toBe(0);
// Empty pre and post.
expect(dp.getAllModules()).toEqual(['', '']);
});

it('should expect a base bundle at initialization', () => {
const dp = new window.DeltaPatcher();
expect(() => {
dp.applyDelta({
base: false,
revisionId: 'hello',
modules: [],
deleted: [],
});
}).toThrow();
});

it('should accept a base bundle at initialization', () => {
const dp = new window.DeltaPatcher();
global.Date = jest.fn();
dp.applyDelta({
base: true,
revisionId: 'rev0',
pre: 'pre0',
post: 'post0',
modules: [[0, '__d(0);']],
});
expect(dp.getLastRevisionId()).toBe('rev0');
expect(dp.getLastModifiedDate()).toBe(global.Date.mock.instances[0]);
expect(dp.getLastNumModifiedFiles()).toBe(1);
expect(dp.getAllModules()).toEqual(['pre0', '__d(0);', 'post0']);
});

it('should accept a delta bundle after a base bundle', () => {
const dp = new window.DeltaPatcher();
dp.applyDelta({
base: true,
revisionId: 'rev0',
pre: 'pre0',
post: 'post0',
modules: [[0, '__d(0);'], [1, '__d(1);'], [2, '__d(2);']],
});
global.Date = jest.fn();
dp.applyDelta({
base: false,
revisionId: 'rev1',
modules: [[1, '__d(1.1);'], [3, '__d(3);']],
deleted: [0],
});
expect(dp.getLastRevisionId()).toBe('rev1');
expect(dp.getLastModifiedDate()).toBe(global.Date.mock.instances[0]);
expect(dp.getLastNumModifiedFiles()).toBe(3);
expect(dp.getAllModules()).toEqual([
'pre0',
'__d(1.1);',
'__d(2);',
'__d(3);',
'post0',
]);
});

it('should accept a base bundle after initialization', () => {
const dp = new window.DeltaPatcher();
dp.applyDelta({
base: true,
revisionId: 'rev0',
pre: 'pre0',
post: 'post0',
modules: [[0, '__d(0);'], [1, '__d(1);'], [2, '__d(2);']],
});
dp.applyDelta({
base: false,
revisionId: 'rev1',
modules: [[1, '__d(1.1);'], [3, '__d(3);']],
deleted: [0],
});
global.Date = jest.fn();
dp.applyDelta({
base: true,
revisionId: 'rev2',
pre: 'pre2',
post: 'post2',
modules: [[4, '__d(4);'], [5, '__d(5);']],
});
expect(dp.getLastRevisionId()).toBe('rev2');
expect(dp.getLastModifiedDate()).toBe(global.Date.mock.instances[0]);
expect(dp.getLastNumModifiedFiles()).toBe(2);
expect(dp.getAllModules()).toEqual(['pre2', '__d(4);', '__d(5);', 'post2']);
});
});
@@ -29,13 +29,7 @@
const data = await fetch(deltaUrl + revisionId);
const bundle = await data.json();

const deltaPatcher = client.applyDelta({
base: bundle.base,
revisionId: bundle.revisionId,
pre: bundle.pre,
post: bundle.post,
modules: new Map(bundle.modules),
});
const deltaPatcher = client.applyDelta(bundle);

let cachedBundle = cachedBundleUrls.get(deltaUrl);

0 comments on commit bea57d8

Please sign in to comment.