From 35785fff1211791e05bb7f607201ad2f1f8f769d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 3 Jan 2017 11:04:01 -0500 Subject: [PATCH] more consistent error logging in CLI --- bin/src/handleError.js | 65 ------------- bin/src/logging.js | 47 +++++++++ bin/src/runRollup.js | 209 ++++++++++++++++++++--------------------- 3 files changed, 151 insertions(+), 170 deletions(-) delete mode 100644 bin/src/handleError.js create mode 100644 bin/src/logging.js diff --git a/bin/src/handleError.js b/bin/src/handleError.js deleted file mode 100644 index 6882108..0000000 --- a/bin/src/handleError.js +++ /dev/null @@ -1,65 +0,0 @@ -import chalk from 'chalk'; - -function stderr ( msg ) { - console.error( msg ); // eslint-disable-line no-console -} - -const handlers = { - MISSING_CONFIG: () => { - stderr( chalk.red( 'Config file must export an options object. See https://github.com/rollup/rollup/wiki/Command-Line-Interface#using-a-config-file' ) ); - }, - - MISSING_EXTERNAL_CONFIG: err => { - stderr( chalk.red( `Could not resolve config file ${err.config}` ) ); - }, - - MISSING_INPUT_OPTION: () => { - stderr( chalk.red( 'You must specify an --input (-i) option' ) ); - }, - - MISSING_OUTPUT_OPTION: () => { - stderr( chalk.red( 'You must specify an --output (-o) option when creating a file with a sourcemap' ) ); - }, - - MISSING_NAME: () => { - stderr( chalk.red( 'You must supply a name for UMD exports (e.g. `--name myModule`)' ) ); - }, - - PARSE_ERROR: err => { - stderr( chalk.red( `Error parsing ${err.file}: ${err.message}` ) ); - }, - - ONE_AT_A_TIME: () => { - stderr( chalk.red( 'rollup can only bundle one file at a time' ) ); - }, - - DUPLICATE_IMPORT_OPTIONS: () => { - stderr( chalk.red( 'use --input, or pass input path as argument' ) ); - }, - - ROLLUP_WATCH_NOT_INSTALLED: () => { - stderr( chalk.red( 'rollup --watch depends on the rollup-watch package, which could not be found. Install it with ' ) + chalk.cyan( 'npm install -D rollup-watch' ) ); - }, - - WATCHER_MISSING_INPUT_OR_OUTPUT: () => { - stderr( chalk.red( 'must specify --input and --output when using rollup --watch' ) ); - } -}; - -export default function handleError ( err, recover ) { - const handler = handlers[ err && err.code ]; - - if ( handler ) { - handler( err ); - } else { - stderr( chalk.red( err.message || err ) ); - - if ( err.stack ) { - stderr( chalk.grey( err.stack ) ); - } - } - - stderr( `Type ${chalk.cyan( 'rollup --help' )} for help, or visit https://github.com/rollup/rollup/wiki` ); - - if ( !recover ) process.exit( 1 ); -} diff --git a/bin/src/logging.js b/bin/src/logging.js new file mode 100644 index 0000000..33b84af --- /dev/null +++ b/bin/src/logging.js @@ -0,0 +1,47 @@ +import chalk from 'chalk'; +import relativeId from '../../src/utils/relativeId.js'; + +if ( !process.stderr.isTTY ) chalk.enabled = false; +const warnSymbol = process.stderr.isTTY ? `⚠️ ` : `Warning: `; +const errorSymbol = process.stderr.isTTY ? `🚨 ` : `Error: `; + +// log to stderr to keep `rollup main.js > bundle.js` from breaking +export const stderr = console.error.bind( console ); // eslint-disable-line no-console + +export function handleWarning ( warning ) { + stderr( `${warnSymbol}${chalk.bold( warning.message )}` ); + + if ( warning.url ) { + stderr( chalk.cyan( warning.url ) ); + } + + if ( warning.loc ) { + stderr( `${relativeId( warning.loc.file )} (${warning.loc.line}:${warning.loc.column})` ); + } + + if ( warning.frame ) { + stderr( chalk.dim( warning.frame ) ); + } + + stderr( '' ); +} + +export function handleError ( err, recover ) { + stderr( `${errorSymbol}${chalk.bold( err.message )}` ); + + if ( err.url ) { + stderr( chalk.cyan( err.url ) ); + } + + if ( err.loc ) { + stderr( `${relativeId( err.loc.file )} (${err.loc.line}:${err.loc.column})` ); + } + + if ( err.frame ) { + stderr( chalk.dim( err.frame ) ); + } + + stderr( '' ); + + if ( !recover ) process.exit( 1 ); +} diff --git a/bin/src/runRollup.js b/bin/src/runRollup.js index 2629d4b..6b0130e 100644 --- a/bin/src/runRollup.js +++ b/bin/src/runRollup.js @@ -2,27 +2,26 @@ import { realpathSync } from 'fs'; import * as rollup from 'rollup'; import relative from 'require-relative'; import chalk from 'chalk'; -import handleError from './handleError'; -import relativeId from '../../src/utils/relativeId.js'; +import { handleWarning, handleError, stderr } from './logging.js'; import SOURCEMAPPING_URL from './sourceMappingUrl.js'; import { install as installSourcemapSupport } from 'source-map-support'; installSourcemapSupport(); -if ( !process.stderr.isTTY ) chalk.enabled = false; -const warnSymbol = process.stderr.isTTY ? `⚠️ ` : `Warning: `; - -// stderr to stderr to keep `rollup main.js > bundle.js` from breaking -const stderr = console.error.bind( console ); // eslint-disable-line no-console - export default function runRollup ( command ) { if ( command._.length > 1 ) { - handleError({ code: 'ONE_AT_A_TIME' }); + handleError({ + code: 'ONE_AT_A_TIME', + message: 'rollup can only bundle one file at a time' + }); } if ( command._.length === 1 ) { if ( command.input ) { - handleError({ code: 'DUPLICATE_IMPORT_OPTIONS' }); + handleError({ + code: 'DUPLICATE_IMPORT_OPTIONS', + message: 'use --input, or pass input path as argument' + }); } command.input = command._[0]; @@ -51,7 +50,10 @@ export default function runRollup ( command ) { config = relative.resolve( pkgName, process.cwd() ); } catch ( err ) { if ( err.code === 'MODULE_NOT_FOUND' ) { - handleError({ code: 'MISSING_EXTERNAL_CONFIG', config }); + handleError({ + code: 'MISSING_EXTERNAL_CONFIG', + message: `Could not resolve config file ${config}` + }); } throw err; @@ -64,37 +66,38 @@ export default function runRollup ( command ) { rollup.rollup({ entry: config, - onwarn: message => { - if ( message.code === 'UNRESOLVED_IMPORT' ) return; - stderr( message.toString() ); + onwarn: warning => { + if ( warning.code === 'UNRESOLVED_IMPORT' ) return; + handleWarning( warning ); } - }).then( bundle => { - const { code } = bundle.generate({ - format: 'cjs' - }); + }) + .then( bundle => { + const { code } = bundle.generate({ + format: 'cjs' + }); - // temporarily override require - const defaultLoader = require.extensions[ '.js' ]; - require.extensions[ '.js' ] = ( m, filename ) => { - if ( filename === config ) { - m._compile( code, filename ); - } else { - defaultLoader( m, filename ); - } - }; + // temporarily override require + const defaultLoader = require.extensions[ '.js' ]; + require.extensions[ '.js' ] = ( m, filename ) => { + if ( filename === config ) { + m._compile( code, filename ); + } else { + defaultLoader( m, filename ); + } + }; - try { const options = require( config ); if ( Object.keys( options ).length === 0 ) { - handleError({ code: 'MISSING_CONFIG' }); + handleError({ + code: 'MISSING_CONFIG', + message: 'Config file must export an options object', + url: 'https://github.com/rollup/rollup/wiki/Command-Line-Interface#using-a-config-file' + }); } execute( options, command ); require.extensions[ '.js' ] = defaultLoader; - } catch ( err ) { - handleError( err ); - } - }) - .catch( stderr ); + }) + .catch( handleError ); } else { execute( {}, command ); } @@ -157,21 +160,7 @@ function execute ( options, command ) { if ( seen.has( str ) ) return; seen.add( str ); - stderr( `${warnSymbol}${chalk.bold( warning.message )}` ); - - if ( warning.url ) { - stderr( chalk.cyan( warning.url ) ); - } - - if ( warning.loc ) { - stderr( `${relativeId( warning.loc.file )} (${warning.loc.line}:${warning.loc.column})` ); - } - - if ( warning.frame ) { - stderr( chalk.dim( warning.frame ) ); - } - - stderr( '' ); + handleWarning( warning ); }; } @@ -184,50 +173,52 @@ function execute ( options, command ) { } }); - try { - if ( command.watch ) { - if ( !options.entry || ( !options.dest && !options.targets ) ) { - handleError({ code: 'WATCHER_MISSING_INPUT_OR_OUTPUT' }); - } + if ( command.watch ) { + if ( !options.entry || ( !options.dest && !options.targets ) ) { + handleError({ + code: 'WATCHER_MISSING_INPUT_OR_OUTPUT', + message: 'must specify --input and --output when using rollup --watch' + }); + } - try { - const watch = relative( 'rollup-watch', process.cwd() ); - const watcher = watch( rollup, options ); + try { + const watch = relative( 'rollup-watch', process.cwd() ); + const watcher = watch( rollup, options ); - watcher.on( 'event', event => { - switch ( event.code ) { - case 'STARTING': // TODO this isn't emitted by newer versions of rollup-watch - stderr( 'checking rollup-watch version...' ); - break; + watcher.on( 'event', event => { + switch ( event.code ) { + case 'STARTING': // TODO this isn't emitted by newer versions of rollup-watch + stderr( 'checking rollup-watch version...' ); + break; - case 'BUILD_START': - stderr( 'bundling...' ); - break; + case 'BUILD_START': + stderr( 'bundling...' ); + break; - case 'BUILD_END': - stderr( 'bundled in ' + event.duration + 'ms. Watching for changes...' ); - break; + case 'BUILD_END': + stderr( 'bundled in ' + event.duration + 'ms. Watching for changes...' ); + break; - case 'ERROR': - handleError( event.error, true ); - break; + case 'ERROR': + handleError( event.error, true ); + break; - default: - stderr( 'unknown event', event ); - } - }); - } catch ( err ) { - if ( err.code === 'MODULE_NOT_FOUND' ) { - err.code = 'ROLLUP_WATCH_NOT_INSTALLED'; + default: + stderr( 'unknown event', event ); } - - handleError( err ); + }); + } catch ( err ) { + if ( err.code === 'MODULE_NOT_FOUND' ) { + handleError({ + code: 'ROLLUP_WATCH_NOT_INSTALLED', + message: 'rollup --watch depends on the rollup-watch package, which could not be found. Install it with npm install -D rollup-watch' + }); } - } else { - bundle( options ).catch( handleError ); + + handleError( err ); } - } catch ( err ) { - handleError( err ); + } else { + bundle( options ).catch( handleError ); } } @@ -244,34 +235,42 @@ function assign ( target, source ) { function bundle ( options ) { if ( !options.entry ) { - handleError({ code: 'MISSING_INPUT_OPTION' }); + handleError({ + code: 'MISSING_INPUT_OPTION', + message: 'You must specify an --input (-i) option' + }); } - return rollup.rollup( options ).then( bundle => { - if ( options.dest ) { - return bundle.write( options ); - } + return rollup.rollup( options ) + .then( bundle => { + if ( options.dest ) { + return bundle.write( options ); + } - if ( options.targets ) { - let result = null; + if ( options.targets ) { + let result = null; - options.targets.forEach( target => { - result = bundle.write( assign( clone( options ), target ) ); - }); + options.targets.forEach( target => { + result = bundle.write( assign( clone( options ), target ) ); + }); - return result; - } + return result; + } - if ( options.sourceMap && options.sourceMap !== 'inline' ) { - handleError({ code: 'MISSING_OUTPUT_OPTION' }); - } + if ( options.sourceMap && options.sourceMap !== 'inline' ) { + handleError({ + code: 'MISSING_OUTPUT_OPTION', + message: 'You must specify an --output (-o) option when creating a file with a sourcemap' + }); + } - let { code, map } = bundle.generate( options ); + let { code, map } = bundle.generate( options ); - if ( options.sourceMap === 'inline' ) { - code += `\n//# ${SOURCEMAPPING_URL}=${map.toUrl()}\n`; - } + if ( options.sourceMap === 'inline' ) { + code += `\n//# ${SOURCEMAPPING_URL}=${map.toUrl()}\n`; + } - process.stdout.write( code ); - }); + process.stdout.write( code ); + }) + .catch( handleError ); }