mirror of https://github.com/status-im/metro.git
Make metro always use the delta bundler
Reviewed By: jeanlauliac Differential Revision: D6208727 fbshipit-source-id: 08589cc92de340d896833cfee2ed14b48b1e6f38
This commit is contained in:
parent
cdfe5b0f20
commit
cecb9bae99
|
@ -27,8 +27,16 @@ jest
|
||||||
.mock('../../lib/GlobalTransformCache')
|
.mock('../../lib/GlobalTransformCache')
|
||||||
.mock('../../DeltaBundler/Serializers');
|
.mock('../../DeltaBundler/Serializers');
|
||||||
|
|
||||||
|
const DeltaBundler = require('../../DeltaBundler');
|
||||||
|
|
||||||
describe('processRequest', () => {
|
describe('processRequest', () => {
|
||||||
let Bundler, Server, AssetServer, symbolicate, Serializers;
|
let Bundler;
|
||||||
|
let Server;
|
||||||
|
let AssetServer;
|
||||||
|
let symbolicate;
|
||||||
|
let Serializers;
|
||||||
|
const lastModified = new Date();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
|
@ -53,7 +61,7 @@ describe('processRequest', () => {
|
||||||
const makeRequest = (reqHandler, requrl, reqOptions) =>
|
const makeRequest = (reqHandler, requrl, reqOptions) =>
|
||||||
new Promise(resolve =>
|
new Promise(resolve =>
|
||||||
reqHandler(
|
reqHandler(
|
||||||
{url: requrl, headers: {}, ...reqOptions},
|
{url: requrl, headers: {host: 'localhost:8081'}, ...reqOptions},
|
||||||
{
|
{
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
headers: {},
|
headers: {},
|
||||||
|
@ -79,6 +87,18 @@ describe('processRequest', () => {
|
||||||
let requestHandler;
|
let requestHandler;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
Serializers.fullBundle.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
bundle: 'this is the source',
|
||||||
|
numModifiedFiles: 38,
|
||||||
|
lastModified,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
Serializers.fullSourceMap.mockReturnValue(
|
||||||
|
Promise.resolve('this is the source map'),
|
||||||
|
);
|
||||||
|
|
||||||
Bundler.prototype.bundle = jest.fn(() =>
|
Bundler.prototype.bundle = jest.fn(() =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
getModules: () => [],
|
getModules: () => [],
|
||||||
|
@ -118,12 +138,12 @@ describe('processRequest', () => {
|
||||||
).then(response => expect(response.body).toEqual('this is the source'));
|
).then(response => expect(response.body).toEqual('this is the source'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns ETag header on request of *.bundle', () => {
|
it('returns Last-Modified header on request of *.bundle', () => {
|
||||||
return makeRequest(
|
return makeRequest(
|
||||||
requestHandler,
|
requestHandler,
|
||||||
'mybundle.bundle?runModule=true',
|
'mybundle.bundle?runModule=true',
|
||||||
).then(response => {
|
).then(response => {
|
||||||
expect(response.getHeader('ETag')).toBeDefined();
|
expect(response.getHeader('Last-Modified')).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,7 +152,7 @@ describe('processRequest', () => {
|
||||||
requestHandler,
|
requestHandler,
|
||||||
'mybundle.bundle?runModule=true',
|
'mybundle.bundle?runModule=true',
|
||||||
).then(response => {
|
).then(response => {
|
||||||
expect(response.getHeader('X-Metro-Files-Changed-Count')).toBeDefined();
|
expect(response.getHeader('X-Metro-Files-Changed-Count')).toEqual('38');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -141,15 +161,15 @@ describe('processRequest', () => {
|
||||||
requestHandler,
|
requestHandler,
|
||||||
'mybundle.bundle?runModule=true',
|
'mybundle.bundle?runModule=true',
|
||||||
).then(response => {
|
).then(response => {
|
||||||
expect(response.getHeader('Content-Length')).toBe(
|
expect(response.getHeader('Content-Length')).toEqual(
|
||||||
Buffer.byteLength(response.body),
|
'' + Buffer.byteLength(response.body),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns 304 on request of *.bundle when if-none-match equals the ETag', () => {
|
it('returns 304 on request of *.bundle when if-modified-since equals Last-Modified', () => {
|
||||||
return makeRequest(requestHandler, 'mybundle.bundle?runModule=true', {
|
return makeRequest(requestHandler, 'mybundle.bundle?runModule=true', {
|
||||||
headers: {'if-none-match': 'this is an etag'},
|
headers: {'if-modified-since': lastModified.toUTCString()},
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
expect(response.statusCode).toEqual(304);
|
expect(response.statusCode).toEqual(304);
|
||||||
});
|
});
|
||||||
|
@ -168,8 +188,9 @@ describe('processRequest', () => {
|
||||||
'index.ios.includeRequire.bundle',
|
'index.ios.includeRequire.bundle',
|
||||||
).then(response => {
|
).then(response => {
|
||||||
expect(response.body).toEqual('this is the source');
|
expect(response.body).toEqual('this is the source');
|
||||||
expect(Bundler.prototype.bundle).toBeCalledWith({
|
expect(Serializers.fullBundle).toBeCalledWith(expect.any(DeltaBundler), {
|
||||||
assetPlugins: [],
|
assetPlugins: [],
|
||||||
|
deltaBundleId: expect.any(String),
|
||||||
dev: true,
|
dev: true,
|
||||||
entryFile: 'index.ios.js',
|
entryFile: 'index.ios.js',
|
||||||
entryModuleOnly: false,
|
entryModuleOnly: false,
|
||||||
|
@ -184,7 +205,7 @@ describe('processRequest', () => {
|
||||||
resolutionResponse: null,
|
resolutionResponse: null,
|
||||||
runBeforeMainModule: ['InitializeCore'],
|
runBeforeMainModule: ['InitializeCore'],
|
||||||
runModule: true,
|
runModule: true,
|
||||||
sourceMapUrl: 'index.ios.includeRequire.map',
|
sourceMapUrl: 'http://localhost:8081/index.ios.includeRequire.map',
|
||||||
unbundle: false,
|
unbundle: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -196,8 +217,9 @@ describe('processRequest', () => {
|
||||||
'index.bundle?platform=ios',
|
'index.bundle?platform=ios',
|
||||||
).then(function(response) {
|
).then(function(response) {
|
||||||
expect(response.body).toEqual('this is the source');
|
expect(response.body).toEqual('this is the source');
|
||||||
expect(Bundler.prototype.bundle).toBeCalledWith({
|
expect(Serializers.fullBundle).toBeCalledWith(expect.any(DeltaBundler), {
|
||||||
assetPlugins: [],
|
assetPlugins: [],
|
||||||
|
deltaBundleId: expect.any(String),
|
||||||
dev: true,
|
dev: true,
|
||||||
entryFile: 'index.js',
|
entryFile: 'index.js',
|
||||||
entryModuleOnly: false,
|
entryModuleOnly: false,
|
||||||
|
@ -212,7 +234,7 @@ describe('processRequest', () => {
|
||||||
resolutionResponse: null,
|
resolutionResponse: null,
|
||||||
runBeforeMainModule: ['InitializeCore'],
|
runBeforeMainModule: ['InitializeCore'],
|
||||||
runModule: true,
|
runModule: true,
|
||||||
sourceMapUrl: 'index.map?platform=ios',
|
sourceMapUrl: 'http://localhost:8081/index.map?platform=ios',
|
||||||
unbundle: false,
|
unbundle: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -224,8 +246,9 @@ describe('processRequest', () => {
|
||||||
'index.bundle?assetPlugin=assetPlugin1&assetPlugin=assetPlugin2',
|
'index.bundle?assetPlugin=assetPlugin1&assetPlugin=assetPlugin2',
|
||||||
).then(function(response) {
|
).then(function(response) {
|
||||||
expect(response.body).toEqual('this is the source');
|
expect(response.body).toEqual('this is the source');
|
||||||
expect(Bundler.prototype.bundle).toBeCalledWith({
|
expect(Serializers.fullBundle).toBeCalledWith(expect.any(DeltaBundler), {
|
||||||
assetPlugins: ['assetPlugin1', 'assetPlugin2'],
|
assetPlugins: ['assetPlugin1', 'assetPlugin2'],
|
||||||
|
deltaBundleId: expect.any(String),
|
||||||
dev: true,
|
dev: true,
|
||||||
entryFile: 'index.js',
|
entryFile: 'index.js',
|
||||||
entryModuleOnly: false,
|
entryModuleOnly: false,
|
||||||
|
@ -241,130 +264,13 @@ describe('processRequest', () => {
|
||||||
runBeforeMainModule: ['InitializeCore'],
|
runBeforeMainModule: ['InitializeCore'],
|
||||||
runModule: true,
|
runModule: true,
|
||||||
sourceMapUrl:
|
sourceMapUrl:
|
||||||
'index.map?assetPlugin=assetPlugin1&assetPlugin=assetPlugin2',
|
'http://localhost:8081/index.map?assetPlugin=assetPlugin1&assetPlugin=assetPlugin2',
|
||||||
unbundle: false,
|
unbundle: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('file changes', () => {
|
|
||||||
it('does not rebuild the bundles that contain a file when that file is changed', () => {
|
|
||||||
const bundleFunc = jest.fn();
|
|
||||||
bundleFunc
|
|
||||||
.mockReturnValueOnce(
|
|
||||||
Promise.resolve({
|
|
||||||
getModules: () => [],
|
|
||||||
getSource: () => 'this is the first source',
|
|
||||||
getSourceMap: () => {},
|
|
||||||
getSourceMapString: () => 'this is the source map',
|
|
||||||
getEtag: () => () => 'this is an etag',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.mockReturnValue(
|
|
||||||
Promise.resolve({
|
|
||||||
getModules: () => [],
|
|
||||||
getSource: () => 'this is the rebuilt source',
|
|
||||||
getSourceMap: () => {},
|
|
||||||
getSourceMapString: () => 'this is the source map',
|
|
||||||
getEtag: () => () => 'this is an etag',
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
Bundler.prototype.bundle = bundleFunc;
|
|
||||||
|
|
||||||
server = new Server(options);
|
|
||||||
|
|
||||||
requestHandler = server.processRequest.bind(server);
|
|
||||||
|
|
||||||
makeRequest(
|
|
||||||
requestHandler,
|
|
||||||
'mybundle.bundle?runModule=true',
|
|
||||||
).done(response => {
|
|
||||||
expect(response.body).toEqual('this is the first source');
|
|
||||||
expect(bundleFunc.mock.calls.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
jest.runAllTicks();
|
|
||||||
|
|
||||||
server.onFileChange('all', options.projectRoots[0] + 'path/file.js');
|
|
||||||
jest.runAllTimers();
|
|
||||||
jest.runAllTicks();
|
|
||||||
|
|
||||||
expect(bundleFunc.mock.calls.length).toBe(1);
|
|
||||||
|
|
||||||
makeRequest(
|
|
||||||
requestHandler,
|
|
||||||
'mybundle.bundle?runModule=true',
|
|
||||||
).done(response =>
|
|
||||||
expect(response.body).toEqual('this is the rebuilt source'),
|
|
||||||
);
|
|
||||||
jest.runAllTicks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(
|
|
||||||
'does not rebuild the bundles that contain a file ' +
|
|
||||||
'when that file is changed, even when hot loading is enabled',
|
|
||||||
() => {
|
|
||||||
const bundleFunc = jest.fn();
|
|
||||||
bundleFunc
|
|
||||||
.mockReturnValueOnce(
|
|
||||||
Promise.resolve({
|
|
||||||
getModules: () => [],
|
|
||||||
getSource: () => 'this is the first source',
|
|
||||||
getSourceMap: () => {},
|
|
||||||
getSourceMapString: () => 'this is the source map',
|
|
||||||
getEtag: () => () => 'this is an etag',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.mockReturnValue(
|
|
||||||
Promise.resolve({
|
|
||||||
getModules: () => [],
|
|
||||||
getSource: () => 'this is the rebuilt source',
|
|
||||||
getSourceMap: () => {},
|
|
||||||
getSourceMapString: () => 'this is the source map',
|
|
||||||
getEtag: () => () => 'this is an etag',
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
Bundler.prototype.bundle = bundleFunc;
|
|
||||||
|
|
||||||
server = new Server(options);
|
|
||||||
server.setHMRFileChangeListener(() => {});
|
|
||||||
|
|
||||||
requestHandler = server.processRequest.bind(server);
|
|
||||||
|
|
||||||
makeRequest(
|
|
||||||
requestHandler,
|
|
||||||
'mybundle.bundle?runModule=true',
|
|
||||||
).done(response => {
|
|
||||||
expect(response.body).toEqual('this is the first source');
|
|
||||||
expect(bundleFunc.mock.calls.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
jest.runAllTicks();
|
|
||||||
|
|
||||||
server.onFileChange('all', options.projectRoots[0] + 'path/file.js');
|
|
||||||
jest.runAllTimers();
|
|
||||||
jest.runAllTicks();
|
|
||||||
|
|
||||||
expect(bundleFunc.mock.calls.length).toBe(1);
|
|
||||||
server.setHMRFileChangeListener(null);
|
|
||||||
|
|
||||||
makeRequest(
|
|
||||||
requestHandler,
|
|
||||||
'mybundle.bundle?runModule=true',
|
|
||||||
).done(response => {
|
|
||||||
expect(response.body).toEqual('this is the rebuilt source');
|
|
||||||
expect(bundleFunc.mock.calls.length).toBe(2);
|
|
||||||
});
|
|
||||||
jest.runAllTicks();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Generate delta bundle endpoint', () => {
|
describe('Generate delta bundle endpoint', () => {
|
||||||
Serializers;
|
|
||||||
|
|
||||||
it('should generate a new delta correctly', () => {
|
it('should generate a new delta correctly', () => {
|
||||||
Serializers.deltaBundle.mockImplementation(async (_, options) => {
|
Serializers.deltaBundle.mockImplementation(async (_, options) => {
|
||||||
expect(options.deltaBundleId).toBe(undefined);
|
expect(options.deltaBundleId).toBe(undefined);
|
||||||
|
|
|
@ -97,7 +97,7 @@ export type Options = {|
|
||||||
+sourceExts: ?Array<string>,
|
+sourceExts: ?Array<string>,
|
||||||
+transformCache: TransformCache,
|
+transformCache: TransformCache,
|
||||||
transformModulePath?: string,
|
transformModulePath?: string,
|
||||||
useDeltaBundler: boolean,
|
useDeltaBundler?: boolean, // TODO: remove this, since it's no longer used
|
||||||
watch?: boolean,
|
watch?: boolean,
|
||||||
workerPath: ?string,
|
workerPath: ?string,
|
||||||
|};
|
|};
|
||||||
|
@ -143,6 +143,8 @@ const FILES_CHANGED_COUNT_REBUILD = -1;
|
||||||
const bundleDeps = new WeakMap();
|
const bundleDeps = new WeakMap();
|
||||||
const NODE_MODULES = `${path.sep}node_modules${path.sep}`;
|
const NODE_MODULES = `${path.sep}node_modules${path.sep}`;
|
||||||
|
|
||||||
|
const USE_DELTA_BUNDLER = true;
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
_opts: {
|
_opts: {
|
||||||
assetExts: Array<string>,
|
assetExts: Array<string>,
|
||||||
|
@ -226,7 +228,6 @@ class Server {
|
||||||
transformCache: options.transformCache,
|
transformCache: options.transformCache,
|
||||||
transformModulePath:
|
transformModulePath:
|
||||||
options.transformModulePath || defaults.transformModulePath,
|
options.transformModulePath || defaults.transformModulePath,
|
||||||
useDeltaBundler: options.useDeltaBundler,
|
|
||||||
watch: options.watch || false,
|
watch: options.watch || false,
|
||||||
workerPath: options.workerPath,
|
workerPath: options.workerPath,
|
||||||
};
|
};
|
||||||
|
@ -448,7 +449,7 @@ class Server {
|
||||||
+minify: boolean,
|
+minify: boolean,
|
||||||
+generateSourceMaps: boolean,
|
+generateSourceMaps: boolean,
|
||||||
}): Promise<Array<string>> {
|
}): Promise<Array<string>> {
|
||||||
if (this._opts.useDeltaBundler) {
|
if (USE_DELTA_BUNDLER) {
|
||||||
const bundleOptions = {
|
const bundleOptions = {
|
||||||
...Server.DEFAULT_BUNDLE_OPTIONS,
|
...Server.DEFAULT_BUNDLE_OPTIONS,
|
||||||
...options,
|
...options,
|
||||||
|
@ -855,7 +856,7 @@ class Server {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._opts.useDeltaBundler) {
|
if (USE_DELTA_BUNDLER) {
|
||||||
if (requestType === 'bundle') {
|
if (requestType === 'bundle') {
|
||||||
await this._processBundleUsingDeltaBundler(req, res);
|
await this._processBundleUsingDeltaBundler(req, res);
|
||||||
return;
|
return;
|
||||||
|
@ -1214,7 +1215,7 @@ class Server {
|
||||||
async _sourceMapForURL(reqUrl: string): Promise<SourceMap> {
|
async _sourceMapForURL(reqUrl: string): Promise<SourceMap> {
|
||||||
const options: DeltaBundlerOptions = this._getOptionsFromUrl(reqUrl);
|
const options: DeltaBundlerOptions = this._getOptionsFromUrl(reqUrl);
|
||||||
|
|
||||||
if (this._opts.useDeltaBundler) {
|
if (USE_DELTA_BUNDLER) {
|
||||||
return await Serializers.fullSourceMapObject(this._deltaBundler, {
|
return await Serializers.fullSourceMapObject(this._deltaBundler, {
|
||||||
...options,
|
...options,
|
||||||
deltaBundleId: this.optionsHash(options),
|
deltaBundleId: this.optionsHash(options),
|
||||||
|
|
|
@ -198,7 +198,6 @@ function toServerOptions(options: Options): ServerOptions {
|
||||||
sourceExts: options.sourceExts,
|
sourceExts: options.sourceExts,
|
||||||
transformCache: options.transformCache || TransformCaching.useTempDir(),
|
transformCache: options.transformCache || TransformCaching.useTempDir(),
|
||||||
transformModulePath: options.transformModulePath,
|
transformModulePath: options.transformModulePath,
|
||||||
useDeltaBundler: options.useDeltaBundler,
|
|
||||||
watch:
|
watch:
|
||||||
typeof options.watch === 'boolean'
|
typeof options.watch === 'boolean'
|
||||||
? options.watch
|
? options.watch
|
||||||
|
|
Loading…
Reference in New Issue