Ensure build process exits with non-zero result on failure
* During build, error is printed out with stack and process exits * During development, initial build behaves as above, however when watching files, errors are displayed but watch process does not exit allowing fixes without a complete rebuild.
This commit is contained in:
parent
b79ecfb5fe
commit
f98ccdee46
3 changed files with 79 additions and 36 deletions
|
@ -11,9 +11,9 @@ const options = JSON.parse(fs.readFileSync('.babelrc'));
|
||||||
onmessage = (ev) => {
|
onmessage = (ev) => {
|
||||||
const t1 = Date.now();
|
const t1 = Date.now();
|
||||||
const sourcefile = path.normalize(ev.data);
|
const sourcefile = path.normalize(ev.data);
|
||||||
let isError = false;
|
let error = null;
|
||||||
let isSkipped = false;
|
let isSkipped = false;
|
||||||
|
|
||||||
fs.readFile(sourcefile, 'utf8', (err, data) => {
|
fs.readFile(sourcefile, 'utf8', (err, data) => {
|
||||||
var transformed;
|
var transformed;
|
||||||
if(sourcefile === 'resource/react-dom.js') {
|
if(sourcefile === 'resource/react-dom.js') {
|
||||||
|
@ -22,24 +22,30 @@ onmessage = (ev) => {
|
||||||
transformed = data;
|
transformed = data;
|
||||||
isSkipped = true;
|
isSkipped = true;
|
||||||
} else {
|
} else {
|
||||||
transformed = babel.transform(data, options).code;
|
try {
|
||||||
|
transformed = babel.transform(data, options).code;
|
||||||
|
} catch(c) {
|
||||||
|
transformed = data;
|
||||||
|
isSkipped = true;
|
||||||
|
error = c.message;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const outfile = path.join('build', sourcefile);
|
const outfile = path.join('build', sourcefile);
|
||||||
isError = !!err;
|
error = error || err;
|
||||||
|
|
||||||
mkdirp(path.dirname(outfile), err => {
|
mkdirp(path.dirname(outfile), err => {
|
||||||
isError = !!err;
|
error = error || err;
|
||||||
|
|
||||||
fs.writeFile(outfile, transformed, err => {
|
fs.writeFile(outfile, transformed, err => {
|
||||||
isError = !!err;
|
error = error || err;
|
||||||
const t2 = Date.now();
|
|
||||||
|
|
||||||
|
const t2 = Date.now();
|
||||||
postMessage({
|
postMessage({
|
||||||
isError,
|
|
||||||
isSkipped,
|
isSkipped,
|
||||||
sourcefile,
|
sourcefile,
|
||||||
outfile,
|
outfile,
|
||||||
|
error,
|
||||||
processingTime: t2 - t1
|
processingTime: t2 - t1
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
87
gulpfile.js
87
gulpfile.js
|
@ -1,6 +1,5 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const gulp = require('gulp');
|
const gulp = require('gulp');
|
||||||
const del = require('del');
|
const del = require('del');
|
||||||
const vfs = require('vinyl-fs');
|
const vfs = require('vinyl-fs');
|
||||||
|
@ -12,15 +11,23 @@ const glob = require('glob');
|
||||||
const Worker = require('tiny-worker');
|
const Worker = require('tiny-worker');
|
||||||
const merge = require('merge-stream');
|
const merge = require('merge-stream');
|
||||||
const tap = require('gulp-tap');
|
const tap = require('gulp-tap');
|
||||||
const rename = require("gulp-rename");
|
const rename = require('gulp-rename');
|
||||||
const browserify = require('browserify');
|
const browserify = require('browserify');
|
||||||
const reactPatcher = require('./gulp/gulp-react-patcher');
|
const reactPatcher = require('./gulp/gulp-react-patcher');
|
||||||
const NODE_ENV = process.env.NODE_ENV;
|
const NODE_ENV = process.env.NODE_ENV;
|
||||||
|
const workers = [];
|
||||||
|
var isExiting = false;
|
||||||
|
|
||||||
const formatDirsforMatcher = dirs => {
|
const formatDirsforMatcher = dirs => {
|
||||||
return dirs.length > 1 ? `{${dirs.join(',')}}` : dirs[0];
|
return dirs.length > 1 ? `{${dirs.join(',')}}` : dirs[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const killAllWorkers = () => {
|
||||||
|
for(let worker of workers) {
|
||||||
|
worker.terminate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// list of folders from where .js files are compiled and non-js files are symlinked
|
// list of folders from where .js files are compiled and non-js files are symlinked
|
||||||
const dirs = [
|
const dirs = [
|
||||||
'chrome',
|
'chrome',
|
||||||
|
@ -72,16 +79,24 @@ const browserifyConfigs = [
|
||||||
const jsGlob = `./\{${dirs.join(',')}\}/**/*.js`;
|
const jsGlob = `./\{${dirs.join(',')}\}/**/*.js`;
|
||||||
const jsGlobIgnore = `./\{${symlinkDirs.concat(copyDirs).join(',')}\}/**/*.js`;
|
const jsGlobIgnore = `./\{${symlinkDirs.concat(copyDirs).join(',')}\}/**/*.js`;
|
||||||
|
|
||||||
function onError(err) {
|
function onError(shouldExit, err) {
|
||||||
gutil.log(gutil.colors.red('Error:'), err);
|
if(shouldExit) {
|
||||||
this.emit('end');
|
isExiting = true;
|
||||||
|
killAllWorkers();
|
||||||
|
throw new Error(err);
|
||||||
|
} else {
|
||||||
|
gutil.log(gutil.colors.red('Error:'), err);
|
||||||
|
this.emit('end');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSuccess(msg) {
|
function onSuccess(msg) {
|
||||||
gutil.log(gutil.colors.green('Build:'), msg);
|
if(!isExiting) {
|
||||||
|
gutil.log(gutil.colors.green('Build:'), msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBrowserify() {
|
function getBrowserify(exitOnError = true) {
|
||||||
const streams = browserifyConfigs.map(config => {
|
const streams = browserifyConfigs.map(config => {
|
||||||
return gulp
|
return gulp
|
||||||
.src(config.src)
|
.src(config.src)
|
||||||
|
@ -89,39 +104,49 @@ function getBrowserify() {
|
||||||
file.contents = browserify(file.path, config.config).bundle();
|
file.contents = browserify(file.path, config.config).bundle();
|
||||||
}))
|
}))
|
||||||
.pipe(rename(config.dest))
|
.pipe(rename(config.dest))
|
||||||
|
.on('error', function(err) { onError.bind(this)(exitOnError, err); })
|
||||||
|
.on('data', file => {
|
||||||
|
onSuccess(`[browserify] ${file.path}`);
|
||||||
|
})
|
||||||
.pipe(gulp.dest('build'));
|
.pipe(gulp.dest('build'));
|
||||||
});
|
});
|
||||||
|
|
||||||
return merge.apply(merge, streams);
|
return merge.apply(merge, streams);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJS(source, sourceIgnore) {
|
function getJS(source, sourceIgnore, exitOnError = true) {
|
||||||
if (sourceIgnore) {
|
if (sourceIgnore) {
|
||||||
source = [source, '!' + sourceIgnore];
|
source = [source, '!' + sourceIgnore];
|
||||||
}
|
}
|
||||||
|
|
||||||
return gulp.src(source, { base: '.' })
|
return gulp.src(source, { base: '.' })
|
||||||
.pipe(babel())
|
.pipe(babel())
|
||||||
.pipe(reactPatcher())
|
.on('error', function(err) { onError.bind(this)(exitOnError, err); })
|
||||||
.on('error', onError)
|
|
||||||
.on('data', file => {
|
.on('data', file => {
|
||||||
onSuccess(`[js] ${file.path}`);
|
onSuccess(`[js] ${file.path}`);
|
||||||
})
|
})
|
||||||
|
.pipe(reactPatcher())
|
||||||
.pipe(gulp.dest('./build'));
|
.pipe(gulp.dest('./build'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJSParallel(source, sourceIgnore) {
|
function getJSParallel(source, sourceIgnore, exitOnError = true) {
|
||||||
const jsFiles = glob.sync(source, { ignore: sourceIgnore });
|
const jsFiles = glob.sync(source, { ignore: sourceIgnore });
|
||||||
const cpuCount = os.cpus().length;
|
const cpuCount = os.cpus().length;
|
||||||
const threadCount = Math.min(cpuCount, jsFiles.length);
|
const threadCount = Math.min(cpuCount, jsFiles.length);
|
||||||
let threadsActive = threadCount;
|
let threadsActive = threadCount;
|
||||||
|
let isError = false;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
for(let i = 0; i < threadCount; i++) {
|
for(let i = 0; i < threadCount; i++) {
|
||||||
let worker = new Worker('gulp/babel-worker.js');
|
let worker = new Worker('gulp/babel-worker.js');
|
||||||
|
workers[i] = worker;
|
||||||
worker.onmessage = ev => {
|
worker.onmessage = ev => {
|
||||||
if(ev.data.isError) {
|
if(ev.data.error) {
|
||||||
reject(`Failed while processing ${ev.data.sourcefile}`);
|
isError = true;
|
||||||
|
let errorMsg = `Failed while processing ${ev.data.sourcefile}: ${ev.data.error}`;
|
||||||
|
NODE_ENV == 'debug' && console.log(`process ${i}: ${errorMsg}`);
|
||||||
|
onError(exitOnError, errorMsg);
|
||||||
|
reject(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_ENV == 'debug' && console.log(`process ${i} took ${ev.data.processingTime} ms to process ${ev.data.sourcefile}`);
|
NODE_ENV == 'debug' && console.log(`process ${i} took ${ev.data.processingTime} ms to process ${ev.data.sourcefile}`);
|
||||||
|
@ -132,11 +157,13 @@ function getJSParallel(source, sourceIgnore) {
|
||||||
}
|
}
|
||||||
let nextFile = jsFiles.pop();
|
let nextFile = jsFiles.pop();
|
||||||
|
|
||||||
if(nextFile) {
|
if(!isError && nextFile) {
|
||||||
|
NODE_ENV == 'debug' && console.log(`process ${i} scheduled to process ${nextFile}`);
|
||||||
worker.postMessage(nextFile);
|
worker.postMessage(nextFile);
|
||||||
} else {
|
} else {
|
||||||
NODE_ENV == 'debug' && console.log(`process ${i} has terminated`);
|
NODE_ENV == 'debug' && console.log(`process ${i} has terminated`);
|
||||||
worker.terminate();
|
worker.terminate();
|
||||||
|
workers.splice(i, 1);
|
||||||
if(!--threadsActive) {
|
if(!--threadsActive) {
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
|
@ -149,7 +176,7 @@ function getJSParallel(source, sourceIgnore) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSymlinks() {
|
function getSymlinks(exitOnError = true) {
|
||||||
const match = symlinkFiles
|
const match = symlinkFiles
|
||||||
.concat(dirs.map(d => `${d}/**`))
|
.concat(dirs.map(d => `${d}/**`))
|
||||||
.concat(symlinkDirs.map(d => `${d}/**`))
|
.concat(symlinkDirs.map(d => `${d}/**`))
|
||||||
|
@ -158,26 +185,27 @@ function getSymlinks() {
|
||||||
|
|
||||||
return gulp
|
return gulp
|
||||||
.src(match, { nodir: true, base: '.', read: false })
|
.src(match, { nodir: true, base: '.', read: false })
|
||||||
.on('error', onError)
|
.on('error', function(err) { onError.bind(this)(exitOnError, err); })
|
||||||
.on('data', file => {
|
.on('data', file => {
|
||||||
onSuccess(`[ln] ${file.path.substr(__dirname.length + 1)}`);
|
onSuccess(`[ln] ${file.path.substr(__dirname.length + 1)}`);
|
||||||
})
|
})
|
||||||
.pipe(vfs.symlink('build/'));
|
.pipe(vfs.symlink('build/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCopy() {
|
function getCopy(exitOnError = true) {
|
||||||
return gulp
|
return gulp
|
||||||
.src(copyDirs.map(d => `${d}/**`), { base: '.' })
|
.src(copyDirs.map(d => `${d}/**`), { base: '.' })
|
||||||
.on('data', file => {
|
.on('data', file => {
|
||||||
onSuccess(`[cp] ${file.path.substr(__dirname.length + 1)}`);
|
onSuccess(`[cp] ${file.path.substr(__dirname.length + 1)}`);
|
||||||
})
|
})
|
||||||
|
.on('error', function(err) { onError.bind(this)(exitOnError, err); })
|
||||||
.pipe(gulp.dest('build/'));
|
.pipe(gulp.dest('build/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSass() {
|
function getSass(exitOnError = true) {
|
||||||
return gulp
|
return gulp
|
||||||
.src('scss/*.scss')
|
.src('scss/*.scss')
|
||||||
.on('error', onError)
|
.on('error', function(err) { onError.bind(this)(exitOnError, err); })
|
||||||
.pipe(sass())
|
.pipe(sass())
|
||||||
.pipe(gulp.dest('./build/chrome/skin/default/zotero/components/'));
|
.pipe(gulp.dest('./build/chrome/skin/default/zotero/components/'));
|
||||||
}
|
}
|
||||||
|
@ -192,7 +220,11 @@ gulp.task('symlink', ['clean'], () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('js', done => {
|
gulp.task('js', done => {
|
||||||
getJSParallel(jsGlob, jsGlobIgnore).then(() => done());
|
getJSParallel(jsGlob, jsGlobIgnore)
|
||||||
|
.then(done)
|
||||||
|
.catch(errorMsg => {
|
||||||
|
onError(errorMsg);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('browserify', () => {
|
gulp.task('browserify', () => {
|
||||||
|
@ -209,16 +241,21 @@ gulp.task('sass', () => {
|
||||||
|
|
||||||
gulp.task('build', ['js', 'sass', 'symlink', 'browserify', 'copy']);
|
gulp.task('build', ['js', 'sass', 'symlink', 'browserify', 'copy']);
|
||||||
|
|
||||||
|
gulp.task('build-clean', ['clean'], () => {
|
||||||
|
gulp.start('build');
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('dev', ['clean'], () => {
|
gulp.task('dev', ['clean'], () => {
|
||||||
var interval = 750;
|
var interval = 750;
|
||||||
|
|
||||||
let watcher = gulp.watch(jsGlob, { interval });
|
gulp.watch(jsGlob, { interval }).on('change', event => {
|
||||||
|
getJS(event.path, jsGlobIgnore, false);
|
||||||
watcher.on('change', function(event) {
|
});
|
||||||
getJS(event.path, jsGlobIgnore);
|
|
||||||
|
gulp.watch('src/styles/*.scss', { interval }).on('change', () => {
|
||||||
|
getSass(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.watch('src/styles/*.scss', { interval }, ['sass']);
|
|
||||||
gulp.start('build');
|
gulp.start('build');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
"main": "",
|
"main": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "./node_modules/.bin/gulp",
|
"start": "./node_modules/.bin/gulp",
|
||||||
"build": "./node_modules/.bin/gulp",
|
"build": "./node_modules/.bin/gulp build-clean",
|
||||||
"sass": "./node_modules/.bin/gulp sass",
|
"sass": "./node_modules/.bin/gulp sass",
|
||||||
"clean": "./node_modules/.bin/gulp clean"
|
"clean": "./node_modules/.bin/gulp clean"
|
||||||
},
|
},
|
||||||
"license": "",
|
"license": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "3.4.7",
|
"bluebird": "3.4.7",
|
||||||
"zotero-web-library": "next",
|
|
||||||
"react": "^15.3.2",
|
"react": "^15.3.2",
|
||||||
"react-dom": "^15.3.2"
|
"react-dom": "^15.3.2",
|
||||||
|
"zotero-web-library": "next"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.24.1",
|
"babel-core": "^6.24.1",
|
||||||
|
|
Loading…
Reference in a new issue