Skip to content

Proof of concept: Transpile in workers #1082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
40 changes: 8 additions & 32 deletions api.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ var EventEmitter = require('events').EventEmitter;
var path = require('path');
var util = require('util');
var commonPathPrefix = require('common-path-prefix');
var uniqueTempDir = require('unique-temp-dir');
var findCacheDir = require('find-cache-dir');
var objectAssign = require('object-assign');
var resolveCwd = require('resolve-cwd');
var debounce = require('lodash.debounce');
Expand All @@ -14,9 +12,10 @@ var Promise = require('bluebird');
var getPort = require('get-port');
var arrify = require('arrify');
var ms = require('ms');
var CachingPrecompiler = require('./lib/caching-precompiler');
var RunStatus = require('./lib/run-status');
var AvaError = require('./lib/ava-error');
var babelBundle = require('./lib/babel/bundle');
var babelConfig = require('./lib/babel/config');
var fork = require('./lib/fork');

function resolveModules(modules) {
Expand Down Expand Up @@ -59,21 +58,14 @@ function Api(options) {
}, options);

this.options.require = resolveModules(this.options.require);
this.options.babel = babelConfig.build(options.babel);
}

util.inherits(Api, EventEmitter);
module.exports = Api;

Api.prototype._runFile = function (file, runStatus, execArgv) {
var hash = this.precompiler.precompileFile(file);
var precompiled = {};
precompiled[file] = hash;

var options = objectAssign({}, this.options, {
precompiled: precompiled
});

var emitter = fork(file, options, execArgv);
var emitter = fork(file, this.options, execArgv);
runStatus.observeFork(emitter);

return emitter;
Expand All @@ -85,7 +77,10 @@ Api.prototype.run = function (files, options) {
return new AvaFiles({cwd: this.options.resolveTestsFrom, files: files})
.findTestFiles()
.then(function (files) {
return self._run(files, options);
return babelBundle.create(self.options.babel).then(function (bundle) {
self.options.bundle = bundle;
return self._run(files, options);
});
});
};

Expand Down Expand Up @@ -113,23 +108,6 @@ Api.prototype._cancelTimeout = function (runStatus) {
runStatus._restartTimer.cancel();
};

Api.prototype._setupPrecompiler = function (files) {
var isCacheEnabled = this.options.cacheEnabled !== false;
var cacheDir = uniqueTempDir();

if (isCacheEnabled) {
cacheDir = findCacheDir({
name: 'ava',
files: files
});
}

this.options.cacheDir = cacheDir;

var isPowerAssertEnabled = this.options.powerAssert !== false;
this.precompiler = new CachingPrecompiler(cacheDir, this.options.babelConfig, isPowerAssertEnabled);
};

Api.prototype._run = function (files, options) {
options = options || {};

Expand All @@ -148,8 +126,6 @@ Api.prototype._run = function (files, options) {
return Promise.resolve(runStatus);
}

this._setupPrecompiler(files);

if (this.options.timeout) {
this._setupTimeout(runStatus);
}
Expand Down
184 changes: 7 additions & 177 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,186 +13,16 @@ var localCLI = resolveCwd('ava/cli');
// see https://github.com/nodejs/node/issues/6624
if (localCLI && path.relative(localCLI, __filename) !== '') {
debug('Using local install of AVA');
require(localCLI);
return;
}

if (debug.enabled) {
require('time-require');
}

var updateNotifier = require('update-notifier');
var figures = require('figures');
var arrify = require('arrify');
var meow = require('meow');
var Promise = require('bluebird');
var pkgConf = require('pkg-conf');
var isCi = require('is-ci');
var hasFlag = require('has-flag');
var colors = require('./lib/colors');
var verboseReporter = require('./lib/reporters/verbose');
var miniReporter = require('./lib/reporters/mini');
var tapReporter = require('./lib/reporters/tap');
var Logger = require('./lib/logger');
var Watcher = require('./lib/watcher');
var babelConfig = require('./lib/babel-config');
var Api = require('./api');

// Bluebird specific
Promise.longStackTraces();

var conf = pkgConf.sync('ava');

var pkgDir = path.dirname(pkgConf.filepath(conf));

try {
conf.babel = babelConfig.validate(conf.babel);
} catch (err) {
console.log('\n ' + err.message);
process.exit(1);
}

var cli = meow([
'Usage',
' ava [<file|directory|glob> ...]',
'',
'Options',
' --init Add AVA to your project',
' --fail-fast Stop after first test failure',
' --serial, -s Run tests serially',
' --tap, -t Generate TAP output',
' --verbose, -v Enable verbose output',
' --no-cache Disable the transpiler cache',
' --no-power-assert Disable Power Assert',
' --match, -m Only run tests with matching title (Can be repeated)',
' --watch, -w Re-run tests when tests and source files change',
' --source, -S Pattern to match source files so tests can be re-run (Can be repeated)',
' --timeout, -T Set global timeout',
' --concurrency, -c Maximum number of test files running at the same time (EXPERIMENTAL)',
'',
'Examples',
' ava',
' ava test.js test2.js',
' ava test-*.js',
' ava test',
' ava --init',
' ava --init foo.js',
'',
'Default patterns when no arguments:',
'test.js test-*.js test/**/*.js **/__tests__/**/*.js **/*.test.js'
], {
string: [
'_',
'timeout',
'source',
'match',
'concurrency'
],
boolean: [
'fail-fast',
'verbose',
'serial',
'tap',
'watch'
],
default: conf,
alias: {
t: 'tap',
v: 'verbose',
s: 'serial',
m: 'match',
w: 'watch',
S: 'source',
T: 'timeout',
c: 'concurrency'
}
});

updateNotifier({pkg: cli.pkg}).notify();

if (cli.flags.init) {
require('ava-init')();
return;
}

if (
((hasFlag('--watch') || hasFlag('-w')) && (hasFlag('--tap') || hasFlag('-t'))) ||
(conf.watch && conf.tap)
) {
console.error(' ' + colors.error(figures.cross) + ' The TAP reporter is not available when using watch mode.');
process.exit(1);
}

if (hasFlag('--require') || hasFlag('-r')) {
console.error(' ' + colors.error(figures.cross) + ' The --require and -r flags are deprecated. Requirements should be configured in package.json - see documentation.');
process.exit(1);
}

var api = new Api({
failFast: cli.flags.failFast,
serial: cli.flags.serial,
require: arrify(conf.require),
cacheEnabled: cli.flags.cache !== false,
powerAssert: cli.flags.powerAssert !== false,
explicitTitles: cli.flags.watch,
match: arrify(cli.flags.match),
babelConfig: conf.babel,
resolveTestsFrom: cli.input.length === 0 ? pkgDir : process.cwd(),
timeout: cli.flags.timeout,
concurrency: cli.flags.concurrency ? parseInt(cli.flags.concurrency, 10) : 0
});

var reporter;

if (cli.flags.tap && !cli.flags.watch) {
reporter = tapReporter();
} else if (cli.flags.verbose || isCi) {
reporter = verboseReporter();
require(localCLI); // eslint-disable-line import/no-dynamic-require
} else {
reporter = miniReporter({watching: cli.flags.watch});
}

reporter.api = api;
var logger = new Logger(reporter);

logger.start();

api.on('test-run', function (runStatus) {
reporter.api = runStatus;
runStatus.on('test', logger.test);
runStatus.on('error', logger.unhandledError);

runStatus.on('stdout', logger.stdout);
runStatus.on('stderr', logger.stderr);
});

var files = cli.input.length ? cli.input : arrify(conf.files);
if (debug.enabled) {
require('time-require'); // eslint-disable-line import/no-unassigned-import
}

if (cli.flags.watch) {
try {
var watcher = new Watcher(logger, api, files, arrify(cli.flags.source));
watcher.observeStdin(process.stdin);
require('./lib/cli').run();
} catch (err) {
if (err.name === 'AvaError') {
// An AvaError may be thrown if chokidar is not installed. Log it nicely.
console.error(' ' + colors.error(figures.cross) + ' ' + err.message);
logger.exit(1);
} else {
// Rethrow so it becomes an uncaught exception.
throw err;
}
console.error('\n ' + err.message);
process.exit(1);
}
} else {
api.run(files)
.then(function (runStatus) {
logger.finish(runStatus);
logger.exit(runStatus.failCount > 0 || runStatus.rejectionCount > 0 || runStatus.exceptionCount > 0 ? 1 : 0);
})
.catch(function (err) {
// Don't swallow exceptions. Note that any expected error should already
// have been logged.
setImmediate(function () {
throw err;
});
});
}
Loading