2017-09-29 12:38:12 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
*
|
2018-02-17 02:24:55 +00:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2017-09-29 12:38:12 +00:00
|
|
|
*
|
|
|
|
* @format
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2017-12-07 01:25:06 +00:00
|
|
|
* This file is a copy of the reference `DeltaPatcher`, located in
|
|
|
|
* metro. The reason to not reuse that file is that in this context
|
|
|
|
* we cannot have flow annotations or CJS syntax (since this file is directly)
|
|
|
|
* injected into a static HTML page.
|
|
|
|
*
|
|
|
|
* TODO: Find a simple and lightweight way to compile `DeltaPatcher` to avoid
|
|
|
|
* having this duplicated file.
|
|
|
|
*/
|
2017-09-29 12:38:12 +00:00
|
|
|
(function(global) {
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is a reference client for the Delta Bundler: it maintains cached the
|
|
|
|
* last patched bundle delta and it's capable of applying new Deltas received
|
|
|
|
* from the Bundler.
|
|
|
|
*/
|
|
|
|
class DeltaPatcher {
|
|
|
|
constructor() {
|
|
|
|
this._lastBundle = {
|
|
|
|
pre: new Map(),
|
|
|
|
post: new Map(),
|
|
|
|
modules: new Map(),
|
|
|
|
};
|
|
|
|
this._initialized = false;
|
|
|
|
this._lastNumModifiedFiles = 0;
|
|
|
|
this._lastModifiedDate = new Date();
|
|
|
|
}
|
|
|
|
|
|
|
|
static get(id) {
|
|
|
|
let deltaPatcher = this._deltaPatchers.get(id);
|
|
|
|
|
|
|
|
if (!deltaPatcher) {
|
|
|
|
deltaPatcher = new DeltaPatcher();
|
|
|
|
this._deltaPatchers.set(id, deltaPatcher);
|
|
|
|
}
|
|
|
|
|
|
|
|
return deltaPatcher;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Applies a Delta Bundle to the current bundle.
|
|
|
|
*/
|
|
|
|
applyDelta(deltaBundle) {
|
|
|
|
// Make sure that the first received delta is a fresh one.
|
|
|
|
if (!this._initialized && !deltaBundle.reset) {
|
|
|
|
throw new Error(
|
|
|
|
'DeltaPatcher should receive a fresh Delta when being initialized',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._initialized = true;
|
|
|
|
|
|
|
|
// Reset the current delta when we receive a fresh delta.
|
|
|
|
if (deltaBundle.reset) {
|
|
|
|
this._lastBundle = {
|
|
|
|
pre: new Map(),
|
|
|
|
post: new Map(),
|
|
|
|
modules: new Map(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
this._lastNumModifiedFiles =
|
|
|
|
deltaBundle.pre.size + deltaBundle.post.size + deltaBundle.delta.size;
|
|
|
|
|
|
|
|
if (this._lastNumModifiedFiles > 0) {
|
|
|
|
this._lastModifiedDate = new Date();
|
|
|
|
}
|
|
|
|
|
|
|
|
this._patchMap(this._lastBundle.pre, deltaBundle.pre);
|
|
|
|
this._patchMap(this._lastBundle.post, deltaBundle.post);
|
|
|
|
this._patchMap(this._lastBundle.modules, deltaBundle.delta);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the number of modified files in the last received Delta. This is
|
|
|
|
* currently used to populate the `X-Metro-Files-Changed-Count` HTTP header
|
|
|
|
* when metro serves the whole JS bundle, and can potentially be removed once
|
|
|
|
* we only send the actual deltas to clients.
|
|
|
|
*/
|
|
|
|
getLastNumModifiedFiles() {
|
|
|
|
return this._lastNumModifiedFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
getLastModifiedDate() {
|
|
|
|
return this._lastModifiedDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
getAllModules() {
|
|
|
|
return [].concat(
|
|
|
|
Array.from(this._lastBundle.pre.values()),
|
|
|
|
Array.from(this._lastBundle.modules.values()),
|
|
|
|
Array.from(this._lastBundle.post.values()),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_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();
|
|
|
|
|
|
|
|
global.DeltaPatcher = DeltaPatcher;
|
|
|
|
})(window);
|