Move progress bar from Bundler to Server

Summary:
Context: I'm trying to add support for sending packager progress events to the client that is downloading the bundle over HTTP multipart response.

In order to do that I need the server to know about these events. Currently the bundler doesn't expose any hooks for monitoring the progress, so this diff introduces `onProgress` option for that.

Reviewed By: davidaurelio

Differential Revision: D3926806

fbshipit-source-id: b7d9c649df4f94ddf5082791209844610650325e
This commit is contained in:
Alex Kotliarskyi 2016-10-03 17:58:21 -07:00 committed by Facebook Github Bot
parent ecd933e73d
commit d9797e2de7
2 changed files with 46 additions and 39 deletions

View File

@ -8,11 +8,11 @@
*/
'use strict';
const Promise = require('promise');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const Promise = require('promise');
const ProgressBar = require('progress');
const Cache = require('../node-haste').Cache;
const Transformer = require('../JSTransformer');
const Resolver = require('../Resolver');
@ -85,10 +85,6 @@ const validateOpts = declareOpts({
type: 'number',
required: false,
},
silent: {
type: 'boolean',
default: false,
},
allowBundleUpdates: {
type: 'boolean',
default: false,
@ -260,6 +256,7 @@ class Bundler {
isolateModuleIDs,
generateSourceMaps,
assetPlugins,
onProgress,
}) {
const onResolutionResponse = response => {
bundle.setMainModuleId(response.getModuleId(getMainModule(response)));
@ -306,6 +303,7 @@ class Bundler {
isolateModuleIDs,
generateSourceMaps,
assetPlugins,
onProgress,
});
}
@ -364,6 +362,7 @@ class Bundler {
onResolutionResponse = noop,
onModuleTransformed = noop,
finalizeBundle = noop,
onProgress = noop,
}) {
const findEventId = Activity.startEvent(
'Transforming modules',
@ -377,17 +376,6 @@ class Bundler {
const modulesByName = Object.create(null);
if (!resolutionResponse) {
let onProgress = noop;
if (process.stdout.isTTY && !this._opts.silent) {
const bar = new ProgressBar('transformed :current/:total (:percent)', {
complete: '=',
incomplete: ' ',
width: 40,
total: 1,
});
onProgress = debouncedTick(bar);
}
resolutionResponse = this.getDependencies({
entryFile,
dev,
@ -775,25 +763,6 @@ function getMainModule({dependencies, numPrependedDependencies = 0}) {
return dependencies[numPrependedDependencies];
}
function debouncedTick(progressBar) {
let n = 0;
let start, total;
return (_, t) => {
total = t;
n += 1;
if (start) {
if (progressBar.curr + n >= total || Date.now() - start > 200) {
progressBar.total = total;
progressBar.tick(n);
start = n = 0;
}
} else {
start = Date.now();
}
};
}
function filterObject(object, blacklist) {
const copied = Object.assign({}, object);
for (const key of blacklist) {

View File

@ -13,6 +13,7 @@ const AssetServer = require('../AssetServer');
const FileWatcher = require('../node-haste').FileWatcher;
const getPlatformExtension = require('../node-haste').getPlatformExtension;
const Bundler = require('../Bundler');
const ProgressBar = require('progress');
const Promise = require('promise');
const SourceMapConsumer = require('source-map').SourceMapConsumer;
@ -158,6 +159,9 @@ const bundleOpts = declareOpts({
type: 'array',
default: [],
},
onProgress: {
type: 'function',
},
});
const dependencyOpts = declareOpts({
@ -192,7 +196,7 @@ const NODE_MODULES = `${path.sep}node_modules${path.sep}`;
class Server {
constructor(options) {
const opts = validateOpts(options);
const opts = this._opts = validateOpts(options);
this._projectRoots = opts.projectRoots;
this._bundles = Object.create(null);
@ -511,8 +515,13 @@ class Server {
).done(() => Activity.endEvent(assetEvent));
}
optionsHash(options) {
// onProgress is a function, can't be serialized
return JSON.stringify(Object.assign({}, options, { onProgress: null }));
}
_useCachedOrUpdateOrCreateBundle(options) {
const optionsJson = JSON.stringify(options);
const optionsJson = this.optionsHash(options);
const bundleFromScratch = () => {
const building = this.buildBundle(options);
this._bundles[optionsJson] = building;
@ -647,6 +656,16 @@ class Server {
details: req.url,
},
);
if (process.stdout.isTTY && !this._opts.silent) {
const bar = new ProgressBar('transformed :current/:total (:percent)', {
complete: '=',
incomplete: ' ',
width: 40,
total: 1,
});
options.onProgress = debouncedTick(bar);
}
debug('Getting bundle for request');
const building = this._useCachedOrUpdateOrCreateBundle(options);
building.then(
@ -691,7 +710,7 @@ class Server {
Activity.endEvent(startReqEventId);
}
},
error => this._handleError(res, JSON.stringify(options), error)
error => this._handleError(res, this.optionsHash(options), error)
).catch(error => {
process.nextTick(() => {
throw error;
@ -867,4 +886,23 @@ function contentsEqual(array, set) {
return array.length === set.size && array.every(set.has, set);
}
function debouncedTick(progressBar) {
let n = 0;
let start, total;
return (_, t) => {
total = t;
n += 1;
if (start) {
if (progressBar.curr + n >= total || Date.now() - start > 200) {
progressBar.total = total;
progressBar.tick(n);
start = n = 0;
}
} else {
start = Date.now();
}
};
}
module.exports = Server;