Add X-Metro-Files-Changed-Count HTTP header to the response when using Delta Bundler

Reviewed By: mjesun

Differential Revision: D5793977

fbshipit-source-id: 9e0783356ca7574077d4eb06489e9837f033d986
This commit is contained in:
Rafael Oleza 2017-09-11 08:22:35 -07:00 committed by Facebook Github Bot
parent bf64ba58d3
commit 197d885ec1
4 changed files with 64 additions and 16 deletions

View File

@ -28,6 +28,7 @@ class DeltaPatcher {
modules: new Map(),
};
_initialized = false;
_lastNumModifiedFiles = 0;
/**
* Applies a Delta Bundle to the current bundle.
@ -51,6 +52,9 @@ class DeltaPatcher {
};
}
this._lastNumModifiedFiles =
deltaBundle.pre.size + deltaBundle.post.size + deltaBundle.delta.size;
this._patchMap(this._lastBundle.pre, deltaBundle.pre);
this._patchMap(this._lastBundle.post, deltaBundle.post);
this._patchMap(this._lastBundle.modules, deltaBundle.delta);
@ -58,17 +62,27 @@ class DeltaPatcher {
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(): number {
return this._lastNumModifiedFiles;
}
/**
* Converts the current delta bundle to a standard string bundle, ready to
* be interpreted by any JS VM.
*/
stringifyCode() {
stringifyCode(): string {
const code = this._getAllModules().map(m => m.code);
return code.join('\n;');
}
stringifyMap({excludeSource}: {excludeSource?: boolean}) {
stringifyMap({excludeSource}: {excludeSource?: boolean}): string {
const mappings = fromRawMappings(this._getAllModules());
return mappings.toString(undefined, {excludeSource});

View File

@ -92,4 +92,29 @@ describe('DeltaPatcher', () => {
.stringifyCode(),
).toMatchSnapshot();
});
it('should return the number of modified files in the last Delta', () => {
deltaPatcher
.applyDelta({
reset: 1,
pre: new Map([[1, {code: 'pre'}]]),
post: new Map([[2, {code: 'post'}]]),
delta: new Map([[3, {code: 'middle'}]]),
})
.stringifyCode();
expect(deltaPatcher.getLastNumModifiedFiles()).toEqual(3);
deltaPatcher
.applyDelta({
reset: 1,
pre: new Map([[1, null]]),
post: new Map(),
delta: new Map([[3, {code: 'different'}]]),
})
.stringifyCode();
// A deleted module counts as a modified file.
expect(deltaPatcher.getLastNumModifiedFiles()).toEqual(2);
});
});

View File

@ -105,14 +105,20 @@ class DeltaBundler {
};
}
async buildFullBundle(options: FullBuildOptions): Promise<string> {
let output = (await this._getDeltaPatcher(options)).stringifyCode();
async buildFullBundle(
options: FullBuildOptions,
): Promise<{bundle: string, numModifiedFiles: number}> {
const deltaPatcher = await this._getDeltaPatcher(options);
let bundle = deltaPatcher.stringifyCode();
if (options.sourceMapUrl) {
output += '//# sourceMappingURL=' + options.sourceMapUrl;
bundle += '//# sourceMappingURL=' + options.sourceMapUrl;
}
return output;
return {
bundle,
numModifiedFiles: deltaPatcher.getLastNumModifiedFiles(),
};
}
async buildFullSourceMap(options: FullBuildOptions): Promise<string> {

View File

@ -924,12 +924,13 @@ class Server {
);
let bundle;
let numModifiedFiles;
try {
bundle = await this._deltaBundler.buildFullBundle({
({bundle, numModifiedFiles} = await this._deltaBundler.buildFullBundle({
...options,
deltaBundleId: this.optionsHash(options),
});
}));
} catch (error) {
this._handleError(res, this.optionsHash(options), error);
@ -947,22 +948,24 @@ class Server {
debug('Responding with 304');
res.writeHead(304);
res.end();
return;
} else {
res.setHeader(FILES_CHANGED_COUNT_HEADER, String(numModifiedFiles));
res.setHeader('Content-Type', 'application/javascript');
res.setHeader('ETag', etag);
res.setHeader('Content-Length', String(Buffer.byteLength(bundle)));
res.end(bundle);
}
res.setHeader('Content-Type', 'application/javascript');
res.setHeader('ETag', etag);
res.setHeader('Content-Length', String(Buffer.byteLength(bundle)));
res.end(bundle);
this._reporter.update({
buildID,
type: 'bundle_build_done',
});
debug('Finished response');
log(createActionEndEntry(requestingBundleLogEntry));
log({
...createActionEndEntry(requestingBundleLogEntry),
outdated_modules: numModifiedFiles,
});
}
async _processSourceMapUsingDeltaBundler(