diff --git a/lib/fs_utils/generate.js b/lib/fs_utils/generate.js index 71efde349..daa0485b8 100644 --- a/lib/fs_utils/generate.js +++ b/lib/fs_utils/generate.js @@ -7,7 +7,7 @@ const fsWriteFile = promisify(require('fs').writeFile); const mkdirp = promisify(require('mkdirp')); const unlink = promisify(require('fs').unlink); const deppack = require('deppack'); // needsProcessing, processFiles -const helpers = require('../helpers'); // flatten, promisifyPlugin +const helpers = require('../helpers'); // flatten, callPlugin const processJob = require('../workers').processJob; const isHmrEnabled = require('../hmr').isEnabled; const hmrGenerate = require('../hmr').generate; @@ -157,7 +157,7 @@ const OptimizeJob = { const optimizerArgs = optimizer.optimize.length === 2 || optimizer.optimize.length === 1 ? [params] : [params.data, params.path]; - return helpers.promisifyPlugin(1, optimizer.optimize) + return helpers.callPlugin(optimizer, optimizer.optimize, 1, optimizerArgs) .apply(optimizer, optimizerArgs); } }; diff --git a/lib/fs_utils/pipeline.js b/lib/fs_utils/pipeline.js index 3c300eeaf..cd79c207f 100644 --- a/lib/fs_utils/pipeline.js +++ b/lib/fs_utils/pipeline.js @@ -4,7 +4,7 @@ const logger = require('loggy'); const debug = require('debug')('brunch:pipeline'); const promisify = require('micro-promisify'); const readFromCache = promisify(require('fcache').readFile); -const promisifyPlugin = require('../helpers').promisifyPlugin; +const callPlugin = require('../helpers').callPlugin; const deppack = require('deppack'); // wrapInModule, exploreDeps, isNpm const processJob = require('../workers').processJob; @@ -27,7 +27,7 @@ const lint = (data, path, linters) => { const reduceLinter = (previousPromise, linter) => { debug(`Linting '${path}' with '${linter.constructor.name}'`); return previousPromise.then(() => { - return promisifyPlugin(2, linter.lint).call(linter, data, path); + return callPlugin(linter, linter.lint, 2, [data, path]); }, err => { return Promise.reject(err); }); @@ -59,8 +59,7 @@ const getDependencies = (data, path, compilerDeps, compiler) => { 'Remove "getDependencies" method.'); } debug(`Dependencies ${path} @ ${name}`); - return promisifyPlugin(2, compiler.getDependencies) - .call(compiler, data, path) + return callPlugin(compiler, compiler.getDependencies, 2, [data, path]) .then(deps => { return deps.map(x => sysPath.normalize(x)); }); @@ -86,7 +85,7 @@ const _compileStatic = (path, source, compiler) => { compilationTime = Date.now(); compiled = typeof _compiled === 'object' ? _compiled.data : _compiled; if (compiler.getDependencies) { - return promisifyPlugin(2, compiler.getDependencies).call(compiler, source, path) + return callPlugin(compiler, compiler.getDependencies, 2, [source, path]) .then(null, error => prepareError('Dependency parsing', error)); } else { return []; @@ -109,12 +108,13 @@ const compilerChain = (previousPromise, compiler) => { const compilerData = compiled || source; const fn = compiler.compile; + // New API: compile({data, path}, callback) // Old API: compile(data, path, callback) const compilerArgs = (fn.length === 2 || fn.length === 1) ? [{data: compilerData, path: path, map: sourceMap}] : [compilerData, path]; - return promisifyPlugin(1, fn).apply(compiler, compilerArgs) + return callPlugin(compiler, fn, 1, compilerArgs, `compile ${path}`) .then(result => { if (result == null) return Promise.resolve(); const isObject = toString.call(result) === '[object Object]'; diff --git a/lib/helpers.js b/lib/helpers.js index ae1f3653b..94f1e3203 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -2,6 +2,7 @@ const getBasename = require('./path').basename; const SourceNode = require('source-map').SourceNode; const promisify = require('micro-promisify'); +const logger = require('loggy'); exports.isWindows = require('os').platform() === 'win32'; @@ -10,6 +11,37 @@ exports.flatten = (array) => [].concat.apply([], array); exports.promisifyPlugin = (arity, fn) => fn.length === arity ? fn : promisify(fn); +exports.safePromise = (promise, intervalTime, timeoutMessage) => { + let resolved; + return new Promise((resolve, reject) => { + promise.then(val => { + if (resolved) return; + resolved = true; + resolve(val); + }, err => { + if (resolved) return; + resolved = true; + reject(err); + }); + + const interval = setInterval(() => { + if (resolved) { + clearInterval(interval); + return; + } + + logger.warn(timeoutMessage); + }, intervalTime); + }); +}; + +exports.callPlugin = (plugin, fn, arity, args, msg) => { + const promise = exports.promisifyPlugin(arity, fn).apply(plugin, args); + if (!msg) msg = 'process'; + + return exports.safePromise(promise, 15000, `${plugin.constructor.name} is taking long to ${msg}`); +}; + exports.asyncFilter = (arr, fn) => { const promises = arr.map(item => fn(item).then(result => [item, result])); return Promise.all(promises).then(data => {