From 9f54af512e0f33563786f3e39b173cf0308e496d Mon Sep 17 00:00:00 2001 From: Michael Cereda Date: Thu, 18 Aug 2016 17:12:28 +0200 Subject: [PATCH 1/6] implementing pretty-cli and optimizin outputs --- package.json | 3 +- scripts/start.js | 119 ++++++++++++---------------------- scripts/utils/cli-template.js | 65 +++++++++++++++++++ scripts/utils/cli.js | 106 ++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+), 80 deletions(-) create mode 100644 scripts/utils/cli-template.js create mode 100644 scripts/utils/cli.js diff --git a/package.json b/package.json index 1b389da8005..e7c715c8152 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,8 @@ "url-loader": "0.5.7", "webpack": "1.13.1", "webpack-dev-server": "1.14.1", - "whatwg-fetch": "1.0.0" + "whatwg-fetch": "1.0.0", + "pretty-cli": "0.0.13" }, "devDependencies": { "bundle-deps": "1.0.0", diff --git a/scripts/start.js b/scripts/start.js index aa68ab40ff3..50cb36f0153 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -21,6 +21,7 @@ var detect = require('detect-port'); var prompt = require('./utils/prompt'); var config = require('../config/webpack.config.dev'); var paths = require('../config/paths'); +var cli = require('./utils/cli'); // Tools like Cloud9 rely on this. var DEFAULT_PORT = process.env.PORT || 3000; @@ -40,37 +41,9 @@ if (isSmokeTest) { }; } -// Some custom utilities to prettify Webpack output. -// This is a little hacky. -// It would be easier if webpack provided a rich error object. -var friendlySyntaxErrorLabel = 'Syntax error:'; -function isLikelyASyntaxError(message) { - return message.indexOf(friendlySyntaxErrorLabel) !== -1; -} -function formatMessage(message) { - return message - // Make some common errors shorter: - .replace( - // Babel syntax error - 'Module build failed: SyntaxError:', - friendlySyntaxErrorLabel - ) - .replace( - // Webpack file not found error - /Module not found: Error: Cannot resolve 'file' or 'directory'/, - 'Module not found:' - ) - // Internal stacks are generally useless so we strip them - .replace(/^\s*at\s.*:\d+:\d+[\s\)]*\n/gm, '') // at ... ...:x:y - // Webpack loader names obscure CSS filenames - .replace('./~/css-loader!./~/postcss-loader!', ''); -} -function clearConsole() { - // This seems to work best on Windows and other systems. - // The intention is to clear the output so you can focus on most recent build. - process.stdout.write('\x1bc'); -} + + function setupCompiler(port) { // "Compiler" is a low-level interface to Webpack. @@ -82,26 +55,32 @@ function setupCompiler(port) { // bundle, so if you refresh, it'll wait instead of serving the old one. // "invalid" is short for "bundle invalidated", it doesn't imply any errors. compiler.plugin('invalid', function() { - clearConsole(); - console.log('Compiling...'); + cli.clear(); + cli.info({type:'title', + name:'WAIT', + message:'Compiling...\n'}); }); // "done" event fires when Webpack has finished recompiling the bundle. // Whether or not you have warnings or errors, you will get this event. compiler.plugin('done', function(stats) { - clearConsole(); + cli.clear(); var hasErrors = stats.hasErrors(); var hasWarnings = stats.hasWarnings(); if (!hasErrors && !hasWarnings) { - console.log(chalk.green('Compiled successfully!')); - console.log(); - console.log('The app is running at:'); - console.log(); - console.log(' ' + chalk.cyan('http://localhost:' + port + '/')); - console.log(); - console.log('Note that the development build is not optimized.'); - console.log('To create a production build, use ' + chalk.cyan('npm run build') + '.'); + // cli.displayHeader(); + cli.success({type:'title', name:'DONE', message:'Compiled successfully!\n'}); + + cli.buildInfo(stats); + + + cli.info('The app is running at http://localhost:' + port + '/'); + console.log(); + cli.note([ + 'Note that the development build is not optimized.', + 'To create a production build, use ' + chalk.cyan('npm run build') + '.']); + return; } @@ -111,39 +90,14 @@ function setupCompiler(port) { // We use stats.toJson({}, true) to make output more compact and readable: // https://github.com/facebookincubator/create-react-app/issues/401#issuecomment-238291901 var json = stats.toJson({}, true); - var formattedErrors = json.errors.map(message => - 'Error in ' + formatMessage(message) - ); - var formattedWarnings = json.warnings.map(message => - 'Warning in ' + formatMessage(message) - ); + if (hasErrors) { - console.log(chalk.red('Failed to compile.')); - console.log(); - if (formattedErrors.some(isLikelyASyntaxError)) { - // If there are any syntax errors, show just them. - // This prevents a confusing ESLint parsing error - // preceding a much more useful Babel syntax error. - formattedErrors = formattedErrors.filter(isLikelyASyntaxError); - } - formattedErrors.forEach(message => { - console.log(message); - console.log(); - }); - // If errors exist, ignore warnings. - return; + cli.displayErrors('Failed to compile.\n', json.errors); + return; } + if (hasWarnings) { - console.log(chalk.yellow('Compiled with warnings.')); - console.log(); - formattedWarnings.forEach(message => { - console.log(message); - console.log(); - }); - // Teach some ESLint tricks. - console.log('You may use special comments to disable some warnings.'); - console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.'); - console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.'); + cli.displayWarnings('Compiled with warnings.\n', json.warnings); } }); } @@ -188,9 +142,14 @@ function addMiddleware(devServer) { })); if (proxy) { if (typeof proxy !== 'string') { - console.log(chalk.red('When specified, "proxy" in package.json must be a string.')); - console.log(chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".')); - console.log(chalk.red('Either remove "proxy" from package.json, or make it a string.')); + cli.error({type:'title', name:'PROXY', + message:[ + 'When specified, "proxy" in package.json must be a string.', + 'Instead, the type of "proxy" was "' + typeof proxy + '".', + 'Either remove "proxy" from package.json, or make it a string.' + ] + }); + process.exit(1); } @@ -244,12 +203,14 @@ function runDevServer(port) { // Launch WebpackDevServer. devServer.listen(port, (err, result) => { if (err) { - return console.log(err); + return cli.error(err); } - clearConsole(); - console.log(chalk.cyan('Starting the development server...')); - console.log(); + cli.clear(); + cli.displayHeader(); + cli.info({type:'title', + name:'WAIT', + message:'Starting the development server...\n'}); openBrowser(port); }); } @@ -267,7 +228,7 @@ detect(DEFAULT_PORT).then(port => { return; } - clearConsole(); + cli.clear(); var question = chalk.yellow('Something is already running on port ' + DEFAULT_PORT + '.') + '\n\nWould you like to run the app on another port instead?'; diff --git a/scripts/utils/cli-template.js b/scripts/utils/cli-template.js new file mode 100644 index 00000000000..3a370f0a2f3 --- /dev/null +++ b/scripts/utils/cli-template.js @@ -0,0 +1,65 @@ +var chalk = require('chalk'); + +function isArray(v){ + if( Object.prototype.toString.call( v ) === '[object Array]' ) { + return true; + } + return false; +} + +function block(msg){ + return ' '+msg+' '; +} + +var types = { + 'info': {initial: 'I', blockBg:['bgBlue','black'], titleColor:'blue'}, + 'error': {initial: 'E', blockBg:['bgRed','white'], titleColor:'red'}, + 'warning': {initial: 'W', blockBg:['bgYellow','black'], titleColor:'yellow'}, + 'success': {initial: 'S', blockBg:['bgGreen','black'], titleColor:'green'}, + 'note': {initial: 'N', blockBg:['bgBlack','yellow'], titleColor:'yellow'}, +} + +var template = {}; + +// template['log'] = function(content){ +// return content; +// } + +function indentLines(lines, spaces){ + if(isArray(lines)) + return lines.join('\n'+ Array(spaces).join(' ')) + return lines; +} +Object.keys(types).map(function(type){ + var _specs = types[type]; + + template[type] = function(content){ + var line; + + if(typeof content !== 'string'){ + var blk; + if(isArray(content)){ + blk = block(_specs.initial) + line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](blk) + +" " + indentLines(content, blk.length+2) + } else { + + if(content.type=='title'){ + blk = block(content.name); + line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](blk) + + " " + chalk[_specs.titleColor](indentLines(content.message, blk.length+2)); + } else { + blk = block(_specs.initial); + line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](blk) + +" " + indentLines(content.message, blk.length); + } + } + } else { + line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](block(_specs.initial)) + +" " + content + } + return line; + } +}) + +module.exports = template; diff --git a/scripts/utils/cli.js b/scripts/utils/cli.js new file mode 100644 index 00000000000..8cb45fae4b5 --- /dev/null +++ b/scripts/utils/cli.js @@ -0,0 +1,106 @@ +var path = require('path'); +var chalk = require('chalk'); + +var pkg = require('../../package.json') + +var friendlySyntaxErrorLabel = 'Syntax error'; +function isLikelyASyntaxError(message) { + return message.indexOf('SyntaxError') !== -1; +} + +function formatMessage(message) { + return message + // Make some common errors shorter: + .replace( + // Babel syntax error + 'Module build failed: SyntaxError:', + friendlySyntaxErrorLabel + ) + .replace( + // Webpack file not found error + /Module not found: Error: Cannot resolve 'file' or 'directory'/, + 'Module not found:' + ) + // Internal stacks are generally useless so we strip them + .replace(/^\s*at\s.*:\d+:\d+[\s\)]*\n/gm, '') // at ... ...:x:y + // Webpack loader names obscure CSS filenames + .replace('./~/css-loader!./~/postcss-loader!', ''); +} + +var cli = require('pretty-cli')({ + template: require('./cli-template') +}); + +cli.addCustomMethod('clear', function(){ + process.stdout.write('\x1bc'); +}) + +cli.addCustomMethod('displayHeader', function(){ + cli.log(pkg.name.toUpperCase() +' '+pkg.version + '\n') +}) + +cli.addCustomMethod('buildInfo', function(stats){ + + 'use strict'; + var buildInfo = []; + try { + var packageData = require(process.cwd() + '/package.json'); + buildInfo.push('Package name: '+packageData.name) + } catch (e) { + // There was no package.json + return; + } + + buildInfo.push('Compiling time: '+ ((stats.endTime-stats.startTime)/ 1000).toFixed(2)+'ms') + buildInfo.push('HASH: '+ stats.hash+'\n') + cli.info(buildInfo) +}) +cli.addCustomMethod('displayWarnings', function(title, messages){ + if(!messages.length) return; + + cli.warning({type:'title', name:'WARNING', message: title}); + + var rx = path.join(__dirname,'../../')+'.*\n'; + var processDir = path.join(process.cwd(),'../') + messages.forEach(message=>{ + var messageString = formatMessage(message) + .replace(new RegExp(rx,''), '\033[0m') + .replace(new RegExp(processDir), './'); + cli.warning('Warning in '+ messageString); + }) + + cli.note(['You may use special comments to disable some warnings.', + 'Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.', + 'Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.' + ]); +}) + +cli.addCustomMethod('displayErrors', function(title, messages){ + if(!messages.length) return; + cli.error({type:'title', name:'ERROR', message: title}); + var isSyntaxError = false; + if (messages.some(isLikelyASyntaxError)) { + // If there are any syntax errors, show just them. + // This prevents a confusing ESLint parsing error + // preceding a much more useful Babel syntax error. + messages = messages.filter(isLikelyASyntaxError); + isSyntaxError = true; + } + + var rx = path.join(__dirname,'../../')+'[^:]*: '; + var processDir = path.join(process.cwd(),'../') + + messages.forEach(message => { + var messageString = formatMessage(message) + .replace(new RegExp(rx,''), ' ') + .replace(new RegExp(processDir), './'); + // if(isSyntaxError){ + cli.error(messageString); + // } else { + // cli.error('Error in ' + messageString); + // } + + }); + +}) +module.exports = cli; From 47c71e5b6374eba024edd8d6443821b931f1191e Mon Sep 17 00:00:00 2001 From: Michael Cereda Date: Thu, 18 Aug 2016 17:24:43 +0200 Subject: [PATCH 2/6] Adding version information --- scripts/utils/cli.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/utils/cli.js b/scripts/utils/cli.js index 8cb45fae4b5..79f4fc7ab95 100644 --- a/scripts/utils/cli.js +++ b/scripts/utils/cli.js @@ -45,7 +45,8 @@ cli.addCustomMethod('buildInfo', function(stats){ var buildInfo = []; try { var packageData = require(process.cwd() + '/package.json'); - buildInfo.push('Package name: '+packageData.name) + buildInfo.push('Name: '+packageData.name) + buildInfo.push('Version: '+packageData.version) } catch (e) { // There was no package.json return; @@ -53,7 +54,7 @@ cli.addCustomMethod('buildInfo', function(stats){ buildInfo.push('Compiling time: '+ ((stats.endTime-stats.startTime)/ 1000).toFixed(2)+'ms') buildInfo.push('HASH: '+ stats.hash+'\n') - cli.info(buildInfo) + cli.info({type:'title', name:'PKG', message:buildInfo}) }) cli.addCustomMethod('displayWarnings', function(title, messages){ if(!messages.length) return; From b4fea92dc7c084dfe5699b58628feb6513efb611 Mon Sep 17 00:00:00 2001 From: Michael Cereda Date: Thu, 18 Aug 2016 17:41:28 +0200 Subject: [PATCH 3/6] minor variable name fix --- scripts/utils/cli-template.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/utils/cli-template.js b/scripts/utils/cli-template.js index 3a370f0a2f3..248a84ca31d 100644 --- a/scripts/utils/cli-template.js +++ b/scripts/utils/cli-template.js @@ -12,11 +12,11 @@ function block(msg){ } var types = { - 'info': {initial: 'I', blockBg:['bgBlue','black'], titleColor:'blue'}, - 'error': {initial: 'E', blockBg:['bgRed','white'], titleColor:'red'}, - 'warning': {initial: 'W', blockBg:['bgYellow','black'], titleColor:'yellow'}, - 'success': {initial: 'S', blockBg:['bgGreen','black'], titleColor:'green'}, - 'note': {initial: 'N', blockBg:['bgBlack','yellow'], titleColor:'yellow'}, + 'info': {initial: 'I', blockColor:['bgBlue','black'], titleColor:'blue'}, + 'error': {initial: 'E', blockColor:['bgRed','white'], titleColor:'red'}, + 'warning': {initial: 'W', blockColor:['bgYellow','black'], titleColor:'yellow'}, + 'success': {initial: 'S', blockColor:['bgGreen','black'], titleColor:'green'}, + 'note': {initial: 'N', blockColor:['bgBlack','yellow'], titleColor:'yellow'}, } var template = {}; @@ -33,29 +33,29 @@ function indentLines(lines, spaces){ Object.keys(types).map(function(type){ var _specs = types[type]; - template[type] = function(content){ - var line; - + template[type] = function(content, override){ + var line, specs={}; + Object.assign(specs, _specs, override) if(typeof content !== 'string'){ var blk; if(isArray(content)){ - blk = block(_specs.initial) - line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](blk) + blk = block(specs.initial) + line = chalk[specs.blockColor[0]][specs.blockColor[1]](blk) +" " + indentLines(content, blk.length+2) } else { if(content.type=='title'){ blk = block(content.name); - line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](blk) - + " " + chalk[_specs.titleColor](indentLines(content.message, blk.length+2)); + line = chalk[specs.blockColor[0]][specs.blockColor[1]](blk) + + " " + chalk[specs.titleColor](indentLines(content.message, blk.length+2)); } else { - blk = block(_specs.initial); - line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](blk) + blk = block(specs.initial); + line = chalk[specs.blockColor[0]][specs.blockColor[1]](blk) +" " + indentLines(content.message, blk.length); } } } else { - line = chalk[_specs.blockBg[0]][_specs.blockBg[1]](block(_specs.initial)) + line = chalk[specs.blockColor[0]][specs.blockColor[1]](block(_specs.initial)) +" " + content } return line; From f0e95149a05b1682210c4eadcf2fcdd676a00747 Mon Sep 17 00:00:00 2001 From: Michael Cereda Date: Thu, 18 Aug 2016 17:52:56 +0200 Subject: [PATCH 4/6] Fixing warning/errors in travis --- scripts/utils/cli-template.js | 8 +++++--- scripts/utils/cli.js | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/utils/cli-template.js b/scripts/utils/cli-template.js index 248a84ca31d..fbc69d12b42 100644 --- a/scripts/utils/cli-template.js +++ b/scripts/utils/cli-template.js @@ -30,7 +30,9 @@ function indentLines(lines, spaces){ return lines.join('\n'+ Array(spaces).join(' ')) return lines; } -Object.keys(types).map(function(type){ + +for(var i=0; i{ var messageString = formatMessage(message) - .replace(new RegExp(rx,''), '\033[0m') + .replace(new RegExp(rx,''), '\\033[0m') .replace(new RegExp(processDir), './'); cli.warning('Warning in '+ messageString); }) From 5f2cbd9256142ad17a686ae034fbd6c4b9060c86 Mon Sep 17 00:00:00 2001 From: Michael Cereda Date: Thu, 18 Aug 2016 18:02:13 +0200 Subject: [PATCH 5/6] Fixing warning/errors in travis --- scripts/utils/cli-template.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/utils/cli-template.js b/scripts/utils/cli-template.js index fbc69d12b42..c5bc3b462d0 100644 --- a/scripts/utils/cli-template.js +++ b/scripts/utils/cli-template.js @@ -30,11 +30,8 @@ function indentLines(lines, spaces){ return lines.join('\n'+ Array(spaces).join(' ')) return lines; } - -for(var i=0; i Date: Thu, 18 Aug 2016 18:18:57 +0200 Subject: [PATCH 6/6] Fixing warning/errors in travis --- package.json | 2 +- scripts/utils/cli.js | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index e7c715c8152..403a69db898 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "webpack": "1.13.1", "webpack-dev-server": "1.14.1", "whatwg-fetch": "1.0.0", - "pretty-cli": "0.0.13" + "pretty-cli": "0.0.14" }, "devDependencies": { "bundle-deps": "1.0.0", diff --git a/scripts/utils/cli.js b/scripts/utils/cli.js index 4f55534cacf..3e68d0b8604 100644 --- a/scripts/utils/cli.js +++ b/scripts/utils/cli.js @@ -78,13 +78,11 @@ cli.addCustomMethod('displayWarnings', function(title, messages){ cli.addCustomMethod('displayErrors', function(title, messages){ if(!messages.length) return; cli.error({type:'title', name:'ERROR', message: title}); - var isSyntaxError = false; if (messages.some(isLikelyASyntaxError)) { // If there are any syntax errors, show just them. // This prevents a confusing ESLint parsing error // preceding a much more useful Babel syntax error. messages = messages.filter(isLikelyASyntaxError); - isSyntaxError = true; } var rx = path.join(__dirname,'../../')+'[^:]*: '; @@ -94,11 +92,8 @@ cli.addCustomMethod('displayErrors', function(title, messages){ var messageString = formatMessage(message) .replace(new RegExp(rx,''), ' ') .replace(new RegExp(processDir), './'); - // if(isSyntaxError){ - cli.error(messageString); - // } else { - // cli.error('Error in ' + messageString); - // } + + cli.error(messageString); });